diff options
Diffstat (limited to 'protocols/Sametime/src')
126 files changed, 38725 insertions, 0 deletions
diff --git a/protocols/Sametime/src/StdAfx.cpp b/protocols/Sametime/src/StdAfx.cpp new file mode 100644 index 0000000000..287357e7a4 --- /dev/null +++ b/protocols/Sametime/src/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/protocols/Sametime/src/StdAfx.h b/protocols/Sametime/src/StdAfx.h new file mode 100644 index 0000000000..a5e7c9b64f --- /dev/null +++ b/protocols/Sametime/src/StdAfx.h @@ -0,0 +1,97 @@ +// stdafx.h : include file for standard system include files,
 +//  or project specific include files that are used frequently, but
 +//      are changed infrequently
 +//
 +
 +#pragma once
 +
 +#pragma warning( disable : 4503 4786 )
 +
 +
 +// Windows
 +#define _WIN32_WINNT 0x501			// for QueueUserAPC
 +#include <windows.h>
 +#include <commctrl.h>
 +#include <process.h>
 +#include <malloc.h>
 +#include <stdio.h>
 +#include <time.h>
 +#include <string.h>
 +
 +
 +// STL
 +#include <queue>		// for	conference.cpp, messaging.cpp
 +#include <string>		// for	conference.cpp, userlist.cpp
 +#include <map>			// for	messaging.cpp
 +#include <fstream>		// for	userlist.cpp
 +#include <iostream>		// for	userlist.cpp
 +
 +
 +// Glib
 +//
 +// Subset of libs and includes from Glib v 2.26 from:
 +// http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.26/glib-dev_2.26.1-1_win32.zip
 +// http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.26/glib-dev_2.26.1-1_win64.zip
 +//
 +//
 +// dll files needed in main Miranda directory:
 +//
 +// x32
 +// libglib-2.0-0.dll   from http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.26/glib_2.26.1-1_win32.zip
 +// intl.dll            from http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime_0.18.1.1-2_win32.zip
 +//
 +// x64
 +// libglib-2.0-0.dll   from http://ftp.gnome.org/pub/gnome/binaries/win64/glib/2.26/glib_2.26.1-1_win64.zip
 +// libintl-8.dll       from http://ftp.gnome.org/pub/gnome/binaries/win64/dependencies/gettext-runtime_0.18.1.1-2_win64.zip
 +// 
 +#include <glib.h>		//for	meanwhile and session.cpp
 +
 +
 +// Menwhile
 +// Sources of Meanwhile v 1.0.2 from
 +// http://meanwhile.sourceforge.net/
 +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>
 +};
 +
 +
 +// Miranda
 +#include <newpluginapi.h>
 +#include <m_system.h>
 +#include <m_protoint.h>
 +#include <m_options.h>
 +#include <m_skin.h>
 +#include <m_clist.h>
 +#include <m_message.h>
 +#include <statusmodes.h>
 +#include <m_langpack.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_clui.h>
 +#include <m_clc.h>
 +#include <m_utils.h>
 +#include <m_idle.h>
 +#include <m_addcontact.h>
 +#include <m_popup.h>
 +#include <m_chat.h>
 +#include <m_genmenu.h>
 +#include <m_icolib.h>
 +
 diff --git a/protocols/Sametime/src/conference.cpp b/protocols/Sametime/src/conference.cpp new file mode 100644 index 0000000000..e72c089e73 --- /dev/null +++ b/protocols/Sametime/src/conference.cpp @@ -0,0 +1,566 @@ +#include "StdAfx.h"
 +#include "sametime.h"
 +
 +
 +
 +void CloseMyConference(CSametimeProto* proto) {
 +	mwConference_destroy(proto->my_conference, 0, Translate("I'm outa here."));
 +	proto->my_conference = 0;
 +}
 +
 +
 +CSametimeProto* getProtoFromMwConference(mwConference* conf)
 +{
 +	mwServiceConference* servConference = mwConference_getServiceConference(conf);
 +	mwService* service = mwServiceConference_getService(servConference);
 +	mwSession* session = mwService_getSession(service);
 +	return (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +}
 +
 +
 +/** 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;
 +	CSametimeProto* proto = getProtoFromMwConference(conf);
 +	proto->debugLog(_T("mwServiceConf_on_invited() start"));
 +
 +	members = mem = mwConference_getMembers(conf);
 +	for (;mem;mem=mem->next) {
 +		if (proto->my_login_info && strcmp(proto->my_login_info->login_id, ((mwLoginInfo*)mem->data)->login_id) == 0) {
 +			proto->debugLog(_T("mwServiceConf_on_invited() already present"));
 +			char* utfs = mir_utf8encodeT(TranslateT("Invitation rejected - already present."));
 +			mwConference_reject(conf, 0, utfs);
 +			mir_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) {
 +		proto->debugLog(_T("mwServiceConf_on_invited() mwConference_accept"));
 +		mwConference_accept(conf);
 +	} else {
 +		proto->debugLog(_T("mwServiceConf_on_invited() mwConference_reject"));
 +		char* temp = mir_utf8encodeT(TranslateT("Your invitation has been rejected."));
 +		mwConference_reject(conf, 0, temp);
 +		mir_free(temp);
 +	}
 +
 +}
 +
 +void CSametimeProto::ClearInviteQueue() {
 +	
 +	debugLog(_T("CSametimeProto::ClearInviteQueue() start"));
 +	if (!my_conference) return;
 +
 +	mwIdBlock idb;
 +	idb.community = 0;
 +
 +	while(invite_queue.size()) {
 +		idb.user = (char *)invite_queue.front().c_str();
 +
 +		MCONTACT hContact = FindContactByUserId(idb.user);
 +		if (!hContact) {
 +			mwSametimeList* user_list = mwSametimeList_new();
 +			char* utfs = mir_utf8encodeT(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);
 +			mir_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 = mir_utf8encodeT(TranslateT("Please join this meeting."));
 +			mwConference_invite(my_conference, &idb, temp);
 +			mir_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) 
 +{	
 +	CSametimeProto* proto = getProtoFromMwConference(conf);
 +	proto->debugLog(_T("mwServiceConf_conf_opened() start"));
 +
 +	TCHAR* tszConfId = mir_utf8decodeT(mwConference_getName(conf));
 +	TCHAR* tszConfTitle = mir_utf8decodeT(mwConference_getTitle(conf));
 +
 +	// create new chat session
 +	GCSESSION gcs = { sizeof(gcs) };
 +	gcs.dwFlags = 0;
 +	gcs.iType = GCW_CHATROOM;
 +	gcs.pszModule = proto->m_szModuleName;
 +	gcs.ptszID = tszConfId;
 +	gcs.ptszName = tszConfTitle;
 +	gcs.dwItemData = 0;
 +
 +	CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcs);
 +	mir_free(tszConfTitle);
 +
 +	//add a group
 +	GCDEST gcd = { proto->m_szModuleName, 0 };
 +	gcd.iType = GC_EVENT_ADDGROUP;
 +	gcd.ptszID = tszConfId;
 +
 +	GCEVENT gce = { sizeof(gce), &gcd };
 +	gce.dwFlags = GCEF_ADDTOLOG;
 +	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) {
 +		proto->debugLog(_T("mwServiceConf_conf_opened() add user"));
 +
 +		TCHAR* tszUserName = mir_utf8decodeT(((mwLoginInfo*)user->data)->user_name);
 +		TCHAR* tszUserId = mir_utf8decodeT(((mwLoginInfo*)user->data)->login_id);
 +		gce.ptszNick = tszUserName;
 +		gce.ptszUID = tszUserId;
 +		gce.bIsMe = (strcmp(((mwLoginInfo*)user->data)->login_id, proto->my_login_info->login_id) == 0);
 +
 +		CallServiceSync(MS_GC_EVENT, 0, (LPARAM) &gce);
 +
 +		mir_free(tszUserName);
 +		mir_free(tszUserId);
 +	}
 +
 +	// 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 == proto->my_conference) {
 +		proto->ClearInviteQueue();
 +	}
 +
 +	mir_free(tszConfId);
 +}
 +
 +/** triggered when a conference is closed. This is typically when
 +  we've left it */
 +void mwServiceConf_conf_closed(mwConference* conf, guint32 reason)
 +{
 +	CSametimeProto* proto = getProtoFromMwConference(conf);
 +	proto->debugLog(_T("mwServiceConf_conf_closed() start"));
 +
 +	TCHAR* tszConfId = mir_utf8decodeT(mwConference_getName(conf));
 +
 +	GCDEST gcd = { proto->m_szModuleName };
 +	gcd.ptszID = tszConfId;
 +	gcd.iType = GC_EVENT_CONTROL;
 +
 +	GCEVENT gce = { sizeof(gce), &gcd };
 +	gce.dwFlags = GCEF_ADDTOLOG;
 +
 +	CallService(MS_GC_EVENT, SESSION_OFFLINE, (LPARAM)&gce);
 +	CallService(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce);
 +	mir_free(tszConfId);
 +}
 +
 +/** triggered when someone joins the conference */
 +void mwServiceConf_on_peer_joined(mwConference* conf, mwLoginInfo* user)
 +{
 +	CSametimeProto* proto = getProtoFromMwConference(conf);
 +	proto->debugLog(_T("mwServiceConf_on_peer_joined() start"));
 +
 +	TCHAR* tszConfId = mir_utf8decodeT(mwConference_getName(conf));
 +
 +	MCONTACT hContact = proto->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 = mir_utf8encodeT(TranslateT("None"));
 +		mwSametimeGroup* stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_NORMAL, utfs);
 +		mwSametimeUser* stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, &idb);
 +
 +		hContact = proto->AddContact(stuser, (proto->options.add_contacts ? false : true));
 +
 +		mwSametimeList_free(user_list);
 +		mir_free(utfs);
 +	}
 +
 +	// add user
 +	GCDEST gcd = { proto->m_szModuleName };
 +	gcd.ptszID = tszConfId;
 +	gcd.iType = GC_EVENT_JOIN;
 +
 +	GCEVENT gce = { sizeof(gce), &gcd };
 +	gce.dwFlags = GCEF_ADDTOLOG;
 +	TCHAR* tszUserName = mir_utf8decodeT(((mwLoginInfo*)user)->user_name);
 +	TCHAR* tszUserId = mir_utf8decodeT(((mwLoginInfo*)user)->login_id);
 +	gce.ptszNick = tszUserName;
 +	gce.ptszUID = tszUserId;
 +	gce.ptszStatus = _T("Normal");
 +	gce.time = (DWORD)time(0);
 +
 +	CallServiceSync(MS_GC_EVENT, 0, (LPARAM) &gce);
 +
 +	mir_free(tszUserName);
 +	mir_free(tszUserId);
 +	mir_free(tszConfId);
 +}
 +
 +/** triggered when someone leaves the conference */
 +void mwServiceConf_on_peer_parted(mwConference* conf, mwLoginInfo* user)
 +{
 +	CSametimeProto* proto = getProtoFromMwConference(conf);
 +	proto->debugLog(_T("mwServiceConf_on_peer_parted() start"));
 +
 +	TCHAR* tszConfId = mir_utf8decodeT(mwConference_getName(conf));
 +
 +	// remove user
 +	GCDEST gcd = { proto->m_szModuleName };
 +	gcd.ptszID = tszConfId;
 +	gcd.iType = GC_EVENT_PART;
 +
 +	GCEVENT gce = { sizeof(gce), &gcd };
 +	gce.dwFlags = GCEF_ADDTOLOG;
 +	TCHAR* tszUserName = mir_utf8decodeT(((mwLoginInfo*)user)->user_name);
 +	TCHAR* tszUserId = mir_utf8decodeT(((mwLoginInfo*)user)->login_id);
 +	gce.ptszNick = tszUserName;
 +	gce.ptszUID = tszUserId;
 +	gce.ptszStatus = _T("Normal");
 +	gce.time = (DWORD)time(0);
 +
 +	CallServiceSync(MS_GC_EVENT, 0, (LPARAM)(GCEVENT *) &gce);
 +
 +	mir_free(tszUserName);
 +	mir_free(tszUserId);
 +	mir_free(tszConfId);
 +}
 +
 +/** triggered when someone says something */
 +void mwServiceConf_on_text(mwConference* conf, mwLoginInfo* user, const char* what)
 +{
 +	CSametimeProto* proto = getProtoFromMwConference(conf);
 +	proto->debugLog(_T("mwServiceConf_on_text() start"));
 +
 +	TCHAR* tszConfId = mir_utf8decodeT(mwConference_getName(conf));
 +
 +	GCDEST gcd = { proto->m_szModuleName };
 +	gcd.ptszID = tszConfId;
 +	gcd.iType = GC_EVENT_MESSAGE;
 +
 +	GCEVENT gce = { sizeof(gce), &gcd };
 +	gce.dwFlags = GCEF_ADDTOLOG;
 +
 +	TCHAR* textT = mir_utf8decodeT(what);
 +	TCHAR* tszUserName = mir_utf8decodeT(((mwLoginInfo*)user)->user_name);
 +	TCHAR* tszUserId = mir_utf8decodeT(((mwLoginInfo*)user)->login_id);
 +	gce.ptszText = textT;
 +	gce.ptszNick = tszUserName;
 +	gce.ptszUID = tszUserId;
 +	gce.time = (DWORD)time(0);
 +
 +	CallService(MS_GC_EVENT, 0, (LPARAM)(GCEVENT *) &gce);
 +
 +	mir_free(textT);
 +	mir_free(tszUserName);
 +	mir_free(tszUserId);
 +	mir_free(tszConfId);
 +}
 +
 +/** typing notification */
 +void mwServiceConf_on_typing(mwConference* conf, mwLoginInfo* who, gboolean typing)
 +{
 +	CSametimeProto* proto = getProtoFromMwConference(conf);
 +	proto->debugLog(_T("mwServiceConf_on_typing() start"));
 +	///TODO unimplemented
 +}
 +
 +/** 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 CSametimeProto::TerminateConference(char* name)
 +{
 +	debugLog(_T("CSametimeProto::TerminateConference() start"));
 +		
 +	GList *conferences, *conf;
 +	conferences = conf = mwServiceConference_getConferences(service_conference);
 +	for (;conf;conf = conf->next) {
 +		if (strcmp(name, mwConference_getName((mwConference*)conf->data)) == 0) {
 +
 +			TCHAR* idt = mir_utf8decodeT(name);
 +			GCDEST gcd = {m_szModuleName, idt, GC_EVENT_CONTROL};
 +
 +			GCEVENT gce = { sizeof(gce), &gcd };
 +			gce.dwFlags = GCEF_ADDTOLOG;
 +			CallService(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce);
 +			
 +			mir_free(idt);
 +		}
 +	}
 +	g_list_free(conferences);
 +}
 +
 +
 +int CSametimeProto::GcEventHook(WPARAM wParam, LPARAM lParam) {
 +
 +	GCHOOK* gch = (GCHOOK*)lParam;
 +
 +	if (strcmp(gch->pDest->pszModule, m_szModuleName) != 0) return 0;
 +
 +	GList *conferences, *conf;
 +	conferences = conf = mwServiceConference_getConferences(service_conference);
 +	for (;conf;conf = conf->next) {
 +		TCHAR* tszConfId = mir_utf8decodeT(mwConference_getName((mwConference*)conf->data));
 +		if (_tcscmp(gch->pDest->ptszID, tszConfId) == 0) {
 +			
 +			switch(gch->pDest->iType) {
 +			case GC_USER_MESSAGE:
 +				{
 +					debugLog(_T("CSametimeProto::GcEventHook() GC_USER_MESSAGE"));
 +					char* utf_msg;
 +					utf_msg = mir_utf8encodeT(gch->ptszText);
 +					mwConference_sendText((mwConference*)conf->data, utf_msg);
 +					mir_free(utf_msg);
 +				}
 +				break;
 +			case GC_SESSION_TERMINATE:
 +				{
 +					if (my_conference == conf->data){
 +						debugLog(_T("CSametimeProto::GcEventHook() GC_SESSION_TERMINATE CloseMyConference"));
 +						CloseMyConference(this);
 +					} else {
 +						debugLog(_T("CSametimeProto::GcEventHook() GC_SESSION_TERMINATE mwConference_destroy"));
 +						char* utfs = mir_utf8encodeT(TranslateT("I'm outa here."));
 +						mwConference_destroy((mwConference*)conf->data, 0, utfs);
 +						mir_free(utfs);
 +					}
 +				}
 +				break;
 +			}
 +
 +			break;
 +		}
 +		mir_free(tszConfId);
 +	}
 +
 +	g_list_free(conferences);
 +
 +	return 0;
 +}
 +
 +int CSametimeProto::ChatDeleted(MCONTACT hContact) {
 +	
 +	if (db_get_b(hContact, m_szModuleName, "ChatRoom", 0) == 0)
 +		return 0;
 +
 +	debugLog(_T("CSametimeProto::ChatDeleted() hContact=[%x]"), hContact);
 +	DBVARIANT dbv;
 +	if (!db_get_s(hContact, m_szModuleName, "ChatRoomID", &dbv)) {
 +		TerminateConference(dbv.pszVal);
 +		db_free(&dbv);
 +	}
 +
 +	return 0;
 +}
 +
 +
 +INT_PTR CSametimeProto::onMenuLeaveChat(WPARAM wParam, LPARAM lParam)
 +{
 +	MCONTACT hContact = (MCONTACT)wParam;
 +	debugLog(_T("CSametimeProto::onMenuLeaveChat() hContact=[%x]"), hContact);
 +	ChatDeleted(hContact);
 +	return 0;
 +}
 +
 +
 +INT_PTR CSametimeProto::onMenuCreateChat(WPARAM wParam, LPARAM lParam)
 +{
 +	MCONTACT hContact = (MCONTACT)wParam;
 +	debugLog(_T("CSametimeProto::onMenuCreateChat() hContact=[%x]"), hContact);
 +	mwAwareIdBlock id_block;
 +	mwIdBlock idb;
 +	if (my_login_info && GetAwareIdFromContact(hContact, &id_block)) {
 +		TCHAR title[512];
 +		TCHAR* ts = mir_utf8decodeT(my_login_info->user_name);
 +		mir_sntprintf(title, SIZEOF(title), TranslateT("%s's Conference"), ts);
 +		mir_free(ts);
 +
 +		idb.user = id_block.user;
 +		idb.community = id_block.community;
 +
 +		invite_queue.push(idb.user);
 +
 +		if (!my_conference) {
 +			debugLog(_T("CSametimeProto::onMenuCreateChat() mwConference_open"));
 +			char* utfs;
 +			my_conference = mwConference_new(service_conference, utfs = mir_utf8encodeT(title));
 +			mwConference_open(my_conference);
 +			mir_free(utfs);
 +		} else {
 +			debugLog(_T("CSametimeProto::onMenuCreateChat() ClearInviteQueue"));
 +			ClearInviteQueue();
 +		}
 +
 +		free(id_block.user);
 +	}
 +
 +	return 0;
 +}
 +
 +int CSametimeProto::PrebuildContactMenu(WPARAM wParam, LPARAM lParam)
 +{
 +	MCONTACT hContact = (MCONTACT)wParam;
 +	debugLog(_T("CSametimeProto::PrebuildContactMenu() hContact=[%x]"), hContact);
 +	CLISTMENUITEM mi = {0};
 +	mi.cbSize = sizeof(mi);
 +	mi.flags = CMIM_FLAGS | (db_get_b(hContact, m_szModuleName, "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 && !db_get_utf(hContact, m_szModuleName, "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);
 +
 +		db_free(&dbv);
 +	}
 +	mi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE | (db_get_b(hContact, m_szModuleName, "ChatRoom", 0) == 0 && not_present ? 0 : CMIF_HIDDEN);
 +	CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hCreateChatMenuItem, (LPARAM)&mi);
 +
 +	return 0;
 +}
 +
 +void CSametimeProto::InitConference()
 +{
 +	debugLog(_T("CSametimeProto::InitConference()"));
 +
 +	my_login_info = mwSession_getLoginInfo(session);
 +
 +	service_conference = mwServiceConference_new(session, &mwConference_handler);
 +	mwSession_addService(session, (struct mwService*)service_conference);
 +
 +	HookProtoEvent(ME_GC_EVENT, &CSametimeProto::GcEventHook);
 +}
 +
 +void CSametimeProto::DeinitConference()
 +{
 +	GList *conferences, *conf;
 +	debugLog(_T("CSametimeProto::DeinitConference()"));
 +
 +	if (service_conference){
 +		conferences = conf = mwServiceConference_getConferences(service_conference);
 +		for (;conf;conf = conf->next) {
 +			if (my_conference == conf->data) CloseMyConference(this);
 +			else {
 +				char* utfs = mir_utf8encodeT(TranslateT("I'm outa here."));
 +				mwConference_destroy((mwConference*)conf->data, 0, utfs);
 +				mir_free(utfs);
 +			}
 +		}
 +		g_list_free(conferences);
 +	}
 +
 +	my_login_info = 0;
 +
 +	mwSession_removeService(session, mwService_CONFERENCE);
 +	if (service_conference){
 +		mwService_free((mwService*)service_conference);
 +		service_conference = 0;
 +	}
 +}
 +
 +void CSametimeProto::InitConferenceMenu()
 +{
 +	debugLog(_T("CSametimeProto::InitConferenceMenu()"));
 +
 +	CreateProtoService(MS_SAMETIME_MENULEAVECHAT, &CSametimeProto::onMenuLeaveChat);
 +	CreateProtoService(MS_SAMETIME_MENUCREATECHAT, &CSametimeProto::onMenuCreateChat);
 +
 +	char service[128];
 +
 +	CLISTMENUITEM mi = { sizeof(mi) };
 +	mi.flags = CMIF_TCHAR | CMIF_NOTOFFLINE;
 +	mi.pszContactOwner = m_szModuleName;
 +	
 +	mi.ptszName = LPGENT("Leave Conference");
 +	mir_snprintf(service, sizeof(service), "%s%s", m_szModuleName, MS_SAMETIME_MENULEAVECHAT);
 +	mi.pszService = service;
 +	mi.icolibItem = GetIconHandle(IDI_ICON_LEAVE);
 +	hLeaveChatMenuItem = Menu_AddContactMenuItem(&mi);
 +
 +	mi.ptszName = LPGENT("Start Conference");
 +	mir_snprintf(service, sizeof(service), "%s%s", m_szModuleName, MS_SAMETIME_MENUCREATECHAT);
 +	mi.pszService = service;
 +	mi.icolibItem = GetIconHandle(IDI_ICON_INVITE);
 +	hCreateChatMenuItem = Menu_AddContactMenuItem(&mi);
 +
 +	HookProtoEvent(ME_CLIST_PREBUILDCONTACTMENU, &CSametimeProto::PrebuildContactMenu);
 +}
 +
 +void CSametimeProto::DeinitConferenceMenu()
 +{
 +	debugLog(_T("CSametimeProto::DeinitConferenceMenu()"));
 +	CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hLeaveChatMenuItem, (LPARAM)0);
 +	CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hCreateChatMenuItem, (LPARAM)0);
 +}
 +
 diff --git a/protocols/Sametime/src/files.cpp b/protocols/Sametime/src/files.cpp new file mode 100644 index 0000000000..a08fa49968 --- /dev/null +++ b/protocols/Sametime/src/files.cpp @@ -0,0 +1,457 @@ +#include "StdAfx.h"
 +#include "sametime.h"
 +
 +
 +CSametimeProto* getProtoFromMwFileTransfer(mwFileTransfer* ft)
 +{
 +	mwServiceFileTransfer* serviceFT = mwFileTransfer_getService(ft);
 +	mwService* service = mwServiceFileTransfer_getService(serviceFT);
 +	mwSession* session = mwService_getSession(service);
 +	return (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +}
 +
 +
 +/** an incoming file transfer has been offered */
 +void mwFileTransfer_offered(mwFileTransfer* ft) {
 +
 +	CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
 +	proto->debugLog(_T("mwFileTransfer_offered() start"));
 +
 +	const mwIdBlock* idb = mwFileTransfer_getUser(ft);
 +	MCONTACT hContact = proto->FindContactByUserId(idb->user);
 +	proto->debugLog(_T("Sametime mwFileTransfer_offered hContact=[%x]"), hContact);
 +
 +	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 = proto->AddContact(stuser, (proto->options.add_contacts ? false : true));
 +	}
 +
 +	proto->ProtoBroadcastAck(hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (HANDLE)ft, 0);
 +
 +	TCHAR* filenameT = mir_utf8decodeT(mwFileTransfer_getFileName(ft));
 +	const char* message = mwFileTransfer_getMessage(ft);
 +	TCHAR descriptionT[512];
 +	if (message) {
 +		TCHAR* messageT = mir_utf8decodeT(message);
 +		mir_sntprintf(descriptionT, SIZEOF(descriptionT), _T("%s - %s"), filenameT, messageT);
 +		mir_free(messageT);
 +	} else {
 +		mir_sntprintf(descriptionT, SIZEOF(descriptionT), _T("%s"), filenameT);
 +	}
 +
 +	PROTORECVFILET pre = {0};
 +	pre.flags = PREF_TCHAR;
 +	pre.fileCount = 1;
 +	pre.timestamp = time(NULL);
 +	pre.tszDescription = descriptionT;
 +	pre.ptszFiles = &filenameT;
 +	pre.lParam = (LPARAM)ft;
 +
 +	ProtoChainRecvFile(hContact, &pre);
 +	
 +	mir_free(filenameT);
 +
 +}
 +
 +//returns 0 if finished with current file
 +int SendFileChunk(CSametimeProto* proto, 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)) {
 +		proto->debugLog(_T("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;
 +}
 +
 +void __cdecl SendThread(LPVOID param) {
 +
 +	mwFileTransfer* ft = (mwFileTransfer*)param;
 +	if (!ft) return;
 +	CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
 +	FileTransferClientData* ftcd = (FileTransferClientData*)mwFileTransfer_getClientData(ft);
 +
 +	proto->debugLog(_T("SendThread() start"));
 +
 +	PROTOFILETRANSFERSTATUS pfts = {0};
 +
 +	pfts.cbSize = sizeof(pfts);
 +	pfts.flags = PFTS_UTF;
 +	pfts.hContact = ftcd->hContact;
 +	if (ftcd->sending == 1){
 +		pfts.flags |= PFTS_SENDING;
 +	}
 +	pfts.pszFiles = NULL;
 +	pfts.totalFiles = ftcd->first->ft_count;
 +	pfts.totalBytes = ftcd->first->totalSize;
 +
 +	while(SendFileChunk(proto, ft, ftcd) && !Miranda_Terminated()) {
 +
 +		pfts.currentFileNumber = ftcd->ft_number;
 +		pfts.totalProgress = ftcd->sizeToHere + mwFileTransfer_getSent(ft);
 +		pfts.szWorkingDir = ftcd->save_path;
 +		pfts.szCurrentFile = (char*)mwFileTransfer_getFileName(ft);
 +		pfts.currentFileSize = mwFileTransfer_getFileSize(ft);
 +		pfts.currentFileProgress = mwFileTransfer_getSent(ft);
 +		pfts.currentFileTime = 0; //?
 +
 +		proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ftcd->hFt, (LPARAM)&pfts);
 +
 +		SleepEx(500,TRUE);
 +	}
 +
 +	proto->ProtoBroadcastAck(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;
 +	
 +	proto->debugLog(_T("SendThread() end"));
 +	return;
 +}
 +
 +/** a file transfer has been fully initiated */
 +void mwFileTransfer_opened(mwFileTransfer* ft) {
 +
 +	CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
 +	FileTransferClientData* ftcd = (FileTransferClientData*)mwFileTransfer_getClientData(ft);
 +
 +	proto->debugLog(_T("Sametime mwFileTransfer_opened start"));
 +
 +	if (ftcd->sending) {
 +		// create a thread to send chunks - since it seems not all clients send acks for each of our chunks!
 +		mir_forkthread(SendThread, (void*)ft);
 +	}
 +}
 +
 +/** 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) {
 +
 +	CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
 +	FileTransferClientData* ftcd = (FileTransferClientData*)mwFileTransfer_getClientData(ft);
 +	proto->debugLog(_T("mwFileTransfer_closed() start"));
 +
 +	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) {
 +				proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ftcd->hFt, 0);
 +			} else {
 +				proto->ProtoBroadcastAck(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) {
 +					proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ftcd->hFt, 0);
 +					mwFileTransfer_offer(ftcd->next->ft);
 +				}
 +			} else {
 +				proto->ProtoBroadcastAck(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) {
 +
 +	CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
 +	FileTransferClientData* ftcd = (FileTransferClientData*)mwFileTransfer_getClientData(ft);
 +	proto->debugLog(_T("mwFileTransfer_recv() start"));
 +
 +	DWORD bytes_written;
 +	if (!WriteFile(ftcd->hFile, data->data, data->len, &bytes_written, 0)) {
 +		proto->debugLog(_T("mwFileTransfer_recv() !WriteFile"));
 +		mwFileTransfer_cancel(ft);
 +		proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ftcd->hFt, 0);
 +		proto->debugLog(_T("mwFileTransfer_recv() ACKRESULT_FAILED"));
 +	} else {
 +		//if (mwFileTransfer_isOpen(ft))
 +			mwFileTransfer_ack(ft); // acknowledge chunk
 +
 +		PROTOFILETRANSFERSTATUS pfts = {0};
 +		pfts.cbSize = sizeof(pfts);
 +		pfts.flags = PFTS_UTF;
 +		pfts.hContact = ftcd->hContact;
 +		if (ftcd->sending == 1){
 +			pfts.flags |= PFTS_SENDING;
 +		}
 +		pfts.pszFiles = NULL;
 +		pfts.totalFiles = 1;
 +		pfts.currentFileNumber = 0;
 +		pfts.totalBytes = mwFileTransfer_getFileSize(ft);
 +		pfts.totalProgress = mwFileTransfer_getSent(ft);
 +		pfts.szWorkingDir = ftcd->save_path;
 +		pfts.szCurrentFile = (char*)mwFileTransfer_getFileName(ft);
 +		pfts.currentFileSize = mwFileTransfer_getFileSize(ft);
 +		pfts.currentFileProgress = mwFileTransfer_getSent(ft);
 +		pfts.currentFileTime = 0; //?
 +
 +		proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ftcd->hFt, (LPARAM)&pfts);
 +		proto->debugLog(_T("mwFileTransfer_recv() ACKRESULT_DATA"));
 +
 +		if (mwFileTransfer_isDone(ft)){
 +			proto->ProtoBroadcastAck(ftcd->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ftcd->hFt, 0);
 +			proto->debugLog(_T("mwFileTransfer_recv() ACKRESULT_SUCCESS"));
 +		}
 +	}
 +
 +}
 +
 +/** 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) {
 +	// see SendThread above - not all clients send us acks
 +	CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
 +	//FileTransferClientData* ftcd = (FileTransferClientData*)mwFileTransfer_getClientData(ft);
 +	proto->debugLog(_T("mwFileTransfer_handle_ack()"));
 +}
 +
 +/** 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 CSametimeProto::SendFilesToUser(MCONTACT hContact, PROTOCHAR** files, const PROTOCHAR* ptszDesc)
 +{
 +	debugLog(_T("CSametimeProto::SendFilesToUser() start"));
 +
 +	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;
 +
 +		TCHAR* fn;
 +		
 +		for (int i = 0; files[i]; i++) {
 +			hFile = CreateFile(files[i], GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
 +			if (hFile != INVALID_HANDLE_VALUE) {
 +				filesize = GetFileSize(hFile, 0);
 +
 +				fn = _tcsrchr(files[i], '\\');
 +				if (fn) fn++;
 +
 +				char* pszDesc_utf8 = mir_utf8encodeT(ptszDesc);
 +				char* pszFile_utf8;
 +				if (fn) {
 +					pszFile_utf8 = mir_utf8encodeT(fn);
 +				} else {
 +					pszFile_utf8 = mir_utf8encodeT(files[i]);
 +				}
 +				ft = mwFileTransfer_new(service_files, &idb, pszDesc_utf8, pszFile_utf8, filesize);
 +				mir_free(pszFile_utf8);
 +				mir_free(pszDesc_utf8);
 +
 +				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 CSametimeProto::AcceptFileTransfer(MCONTACT hContact, HANDLE hFt, char* save_path)
 +{
 +
 +	mwFileTransfer* ft = (mwFileTransfer*)(hFt);
 +	CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
 +	debugLog(_T("CSametimeProto::AcceptFileTransfer() start"));
 +
 +	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) {
 +		debugLog(_T("CSametimeProto::AcceptFileTransfer() INVALID_HANDLE_VALUE"));
 +		mwFileTransfer_close(ft, mwFileTransfer_ERROR);
 +		return 0;
 +	}
 +	
 +	ftcd->hContact = hContact;
 +
 +	mwFileTransfer_setClientData(ft, (gpointer)ftcd, 0);
 +
 +	mwFileTransfer_accept(ft);
 +	return hFt;
 +}
 +
 +
 +void CSametimeProto::RejectFileTransfer(HANDLE hFt)
 +{
 +	mwFileTransfer* ft = (mwFileTransfer*)hFt;
 +	CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
 +	debugLog(_T("CSametimeProto::RejectFileTransfer() start"));
 +
 +	mwFileTransfer_reject(ft);
 +}
 +
 +
 +void CSametimeProto::CancelFileTransfer(HANDLE hFt)
 +{
 +	mwFileTransfer* ft = (mwFileTransfer*)hFt;
 +	CSametimeProto* proto = getProtoFromMwFileTransfer(ft);
 +	debugLog(_T("CSametimeProto::CancelFileTransfer() start"));
 +
 +	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 CSametimeProto::InitFiles()
 +{
 +	debugLog(_T("CSametimeProto::InitFiles()"));
 +	mwSession_addService(session, (mwService*)(service_files = mwServiceFileTransfer_new(session, &mwFileTransfer_handler)));
 +}
 +
 +void CSametimeProto::DeinitFiles()
 +{
 +	debugLog(_T("CSametimeProto::DeinitFiles()"));
 +	mwSession_removeService(session, mwService_FILE_TRANSFER);
 +	mwService_free((mwService*)service_files);
 +	service_files = 0;
 +}
 +
 diff --git a/protocols/Sametime/src/glib/include/glib.h b/protocols/Sametime/src/glib/include/glib.h new file mode 100644 index 0000000000..06d0190b24 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib.h @@ -0,0 +1,99 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __G_LIB_H__ +#define __G_LIB_H__ + +#define __GLIB_H_INSIDE__ + +#include <glib/galloca.h> +#include <glib/garray.h> +#include <glib/gasyncqueue.h> +#include <glib/gatomic.h> +#include <glib/gbacktrace.h> +#include <glib/gbase64.h> +#include <glib/gbitlock.h> +#include <glib/gbookmarkfile.h> +#include <glib/gcache.h> +#include <glib/gchecksum.h> +#include <glib/gcompletion.h> +#include <glib/gconvert.h> +#include <glib/gdataset.h> +#include <glib/gdate.h> +#include <glib/gdatetime.h> +#include <glib/gdir.h> +#include <glib/gerror.h> +#include <glib/gfileutils.h> +#include <glib/ghash.h> +#include <glib/ghook.h> +#include <glib/ghostutils.h> +#include <glib/giochannel.h> +#include <glib/gkeyfile.h> +#include <glib/glist.h> +#include <glib/gmacros.h> +#include <glib/gmain.h> +#include <glib/gmappedfile.h> +#include <glib/gmarkup.h> +#include <glib/gmem.h> +#include <glib/gmessages.h> +#include <glib/gnode.h> +#include <glib/goption.h> +#include <glib/gpattern.h> +#include <glib/gpoll.h> +#include <glib/gprimes.h> +#include <glib/gqsort.h> +#include <glib/gquark.h> +#include <glib/gqueue.h> +#include <glib/grand.h> +#include <glib/grel.h> +#include <glib/gregex.h> +#include <glib/gscanner.h> +#include <glib/gsequence.h> +#include <glib/gshell.h> +#include <glib/gslice.h> +#include <glib/gslist.h> +#include <glib/gspawn.h> +#include <glib/gstrfuncs.h> +#include <glib/gstring.h> +#include <glib/gtestutils.h> +#include <glib/gthread.h> +#include <glib/gthreadpool.h> +#include <glib/gtimer.h> +#include <glib/gtimezone.h> +#include <glib/gtree.h> +#include <glib/gtypes.h> +#include <glib/gunicode.h> +#include <glib/gurifuncs.h> +#include <glib/gutils.h> +#include <glib/gvarianttype.h> +#include <glib/gvariant.h> +#ifdef G_PLATFORM_WIN32 +#include <glib/gwin32.h> +#endif + +#undef __GLIB_H_INSIDE__ + +#endif /* __G_LIB_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/galloca.h b/protocols/Sametime/src/glib/include/glib/galloca.h new file mode 100644 index 0000000000..8876836a6f --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/galloca.h @@ -0,0 +1,110 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_ALLOCA_H__ +#define __G_ALLOCA_H__ + +#include <glib/gtypes.h> + +#ifdef  __GNUC__ +/* GCC does the right thing */ +# undef alloca +# define alloca(size)   __builtin_alloca (size) +#elif defined (GLIB_HAVE_ALLOCA_H) +/* a native and working alloca.h is there */  +# include <alloca.h> +#else /* !__GNUC__ && !GLIB_HAVE_ALLOCA_H */ +# if defined(_MSC_VER) || defined(__DMC__) +#  include <malloc.h> +#  define alloca _alloca +# else /* !_MSC_VER && !__DMC__ */ +#  ifdef _AIX +#   pragma alloca +#  else /* !_AIX */ +#   ifndef alloca /* predefined by HP cc +Olibcalls */ +G_BEGIN_DECLS +char *alloca (); +G_END_DECLS +#   endif /* !alloca */ +#  endif /* !_AIX */ +# endif /* !_MSC_VER && !__DMC__ */ +#endif /* !__GNUC__ && !GLIB_HAVE_ALLOCA_H */ + +/** + * g_alloca: + * @size: number of bytes to allocate. + *  + * Allocates @size bytes on the stack; these bytes will be freed when the current + * stack frame is cleaned up. This macro essentially just wraps the alloca() + * function present on most UNIX variants. + * Thus it provides the same advantages and pitfalls as alloca(): + * <variablelist> + *   <varlistentry><term></term><listitem><para> + *     + alloca() is very fast, as on most systems it's implemented by just adjusting + *     the stack pointer register. + *   </para></listitem></varlistentry> + *   <varlistentry><term></term><listitem><para> + *     + It doesn't cause any memory fragmentation, within its scope, separate alloca() + *     blocks just build up and are released together at function end. + *   </para></listitem></varlistentry> + *   <varlistentry><term></term><listitem><para> + *     - Allocation sizes have to fit into the current stack frame. For instance in a + *       threaded environment on Linux, the per-thread stack size is limited to 2 Megabytes, + *       so be sparse with alloca() uses. + *   </para></listitem></varlistentry> + *   <varlistentry><term></term><listitem><para> + *     - Allocation failure due to insufficient stack space is not indicated with a %NULL + *       return like e.g. with malloc(). Instead, most systems probably handle it the same + *       way as out of stack space situations from infinite function recursion, i.e. + *       with a segmentation fault. + *   </para></listitem></varlistentry> + *   <varlistentry><term></term><listitem><para> + *     - Special care has to be taken when mixing alloca() with GNU C variable sized arrays. + *       Stack space allocated with alloca() in the same scope as a variable sized array + *       will be freed together with the variable sized array upon exit of that scope, and + *       not upon exit of the enclosing function scope. + *   </para></listitem></varlistentry> + * </variablelist> + *  + * Returns: space for @size bytes, allocated on the stack + */ +#define g_alloca(size)		 alloca (size) +/** + * g_newa: + * @struct_type: Type of memory chunks to be allocated + * @n_structs: Number of chunks to be allocated + *  + * Wraps g_alloca() in a more typesafe manner. + *  + * Returns: Pointer to stack space for @n_structs chunks of type @struct_type + */ +#define g_newa(struct_type, n_structs)	((struct_type*) g_alloca (sizeof (struct_type) * (gsize) (n_structs))) + +#endif /* __G_ALLOCA_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/garray.h b/protocols/Sametime/src/glib/include/glib/garray.h new file mode 100644 index 0000000000..6bc51f797e --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/garray.h @@ -0,0 +1,179 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_ARRAY_H__ +#define __G_ARRAY_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +typedef struct _GArray		GArray; +typedef struct _GByteArray	GByteArray; +typedef struct _GPtrArray	GPtrArray; + +struct _GArray +{ +  gchar *data; +  guint len; +}; + +struct _GByteArray +{ +  guint8 *data; +  guint	  len; +}; + +struct _GPtrArray +{ +  gpointer *pdata; +  guint	    len; +}; + +/* Resizable arrays. remove fills any cleared spot and shortens the + * array, while preserving the order. remove_fast will distort the + * order by moving the last element to the position of the removed. + */ + +#define g_array_append_val(a,v)	  g_array_append_vals (a, &(v), 1) +#define g_array_prepend_val(a,v)  g_array_prepend_vals (a, &(v), 1) +#define g_array_insert_val(a,i,v) g_array_insert_vals (a, i, &(v), 1) +#define g_array_index(a,t,i)      (((t*) (void *) (a)->data) [(i)]) + +GArray* g_array_new               (gboolean          zero_terminated, +				   gboolean          clear_, +				   guint             element_size); +GArray* g_array_sized_new         (gboolean          zero_terminated, +				   gboolean          clear_, +				   guint             element_size, +				   guint             reserved_size); +gchar*  g_array_free              (GArray           *array, +				   gboolean          free_segment); +GArray *g_array_ref               (GArray           *array); +void    g_array_unref             (GArray           *array); +guint   g_array_get_element_size  (GArray           *array); +GArray* g_array_append_vals       (GArray           *array, +				   gconstpointer     data, +				   guint             len); +GArray* g_array_prepend_vals      (GArray           *array, +				   gconstpointer     data, +				   guint             len); +GArray* g_array_insert_vals       (GArray           *array, +				   guint             index_, +				   gconstpointer     data, +				   guint             len); +GArray* g_array_set_size          (GArray           *array, +				   guint             length); +GArray* g_array_remove_index      (GArray           *array, +				   guint             index_); +GArray* g_array_remove_index_fast (GArray           *array, +				   guint             index_); +GArray* g_array_remove_range      (GArray           *array, +				   guint             index_, +				   guint             length); +void    g_array_sort              (GArray           *array, +				   GCompareFunc      compare_func); +void    g_array_sort_with_data    (GArray           *array, +				   GCompareDataFunc  compare_func, +				   gpointer          user_data); + +/* Resizable pointer array.  This interface is much less complicated + * than the above.  Add appends a pointer.  Remove fills any cleared  + * spot and shortens the array. remove_fast will again distort order.   + */ +#define    g_ptr_array_index(array,index_) ((array)->pdata)[index_] +GPtrArray* g_ptr_array_new                (void); +GPtrArray* g_ptr_array_new_with_free_func (GDestroyNotify    element_free_func); +GPtrArray* g_ptr_array_sized_new          (guint             reserved_size); +gpointer*  g_ptr_array_free               (GPtrArray        *array, +					   gboolean          free_seg); +GPtrArray* g_ptr_array_ref                (GPtrArray        *array); +void       g_ptr_array_unref              (GPtrArray        *array); +void       g_ptr_array_set_free_func      (GPtrArray        *array, +                                           GDestroyNotify    element_free_func); +void       g_ptr_array_set_size           (GPtrArray        *array, +					   gint              length); +gpointer   g_ptr_array_remove_index       (GPtrArray        *array, +					   guint             index_); +gpointer   g_ptr_array_remove_index_fast  (GPtrArray        *array, +					   guint             index_); +gboolean   g_ptr_array_remove             (GPtrArray        *array, +					   gpointer          data); +gboolean   g_ptr_array_remove_fast        (GPtrArray        *array, +					   gpointer          data); +void       g_ptr_array_remove_range       (GPtrArray        *array, +					   guint             index_, +					   guint             length); +void       g_ptr_array_add                (GPtrArray        *array, +					   gpointer          data); +void       g_ptr_array_sort               (GPtrArray        *array, +					   GCompareFunc      compare_func); +void       g_ptr_array_sort_with_data     (GPtrArray        *array, +					   GCompareDataFunc  compare_func, +					   gpointer          user_data); +void       g_ptr_array_foreach            (GPtrArray        *array, +					   GFunc             func, +					   gpointer          user_data); + + +/* Byte arrays, an array of guint8.  Implemented as a GArray, + * but type-safe. + */ + +GByteArray* g_byte_array_new               (void); +GByteArray* g_byte_array_sized_new         (guint             reserved_size); +guint8*     g_byte_array_free              (GByteArray       *array, +					    gboolean          free_segment); +GByteArray *g_byte_array_ref               (GByteArray       *array); +void        g_byte_array_unref             (GByteArray       *array); +GByteArray* g_byte_array_append            (GByteArray       *array, +					    const guint8     *data, +					    guint             len); +GByteArray* g_byte_array_prepend           (GByteArray       *array, +					    const guint8     *data, +					    guint             len); +GByteArray* g_byte_array_set_size          (GByteArray       *array, +					    guint             length); +GByteArray* g_byte_array_remove_index      (GByteArray       *array, +					    guint             index_); +GByteArray* g_byte_array_remove_index_fast (GByteArray       *array, +					    guint             index_); +GByteArray* g_byte_array_remove_range      (GByteArray       *array, +					    guint             index_, +					    guint             length); +void        g_byte_array_sort              (GByteArray       *array, +					    GCompareFunc      compare_func); +void        g_byte_array_sort_with_data    (GByteArray       *array, +					    GCompareDataFunc  compare_func, +					    gpointer          user_data); + +G_END_DECLS + +#endif /* __G_ARRAY_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gasyncqueue.h b/protocols/Sametime/src/glib/include/glib/gasyncqueue.h new file mode 100644 index 0000000000..9da43e36da --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gasyncqueue.h @@ -0,0 +1,120 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_ASYNCQUEUE_H__ +#define __G_ASYNCQUEUE_H__ + +#include <glib/gthread.h> + +G_BEGIN_DECLS + +typedef struct _GAsyncQueue GAsyncQueue; + +/* Asyncronous Queues, can be used to communicate between threads */ + +/* Get a new GAsyncQueue with the ref_count 1 */ +GAsyncQueue*  g_async_queue_new                 (void); + +GAsyncQueue*  g_async_queue_new_full            (GDestroyNotify item_free_func); + +/* Lock and unlock a GAsyncQueue. All functions lock the queue for + * themselves, but in certain cirumstances you want to hold the lock longer, + * thus you lock the queue, call the *_unlocked functions and unlock it again. + */ +void         g_async_queue_lock                 (GAsyncQueue      *queue); +void         g_async_queue_unlock               (GAsyncQueue      *queue); + +/* Ref and unref the GAsyncQueue. */ +GAsyncQueue* g_async_queue_ref                  (GAsyncQueue      *queue); +void         g_async_queue_unref                (GAsyncQueue      *queue); + +#ifndef G_DISABLE_DEPRECATED +/* You don't have to hold the lock for calling *_ref and *_unref anymore. */ +void         g_async_queue_ref_unlocked         (GAsyncQueue      *queue); +void         g_async_queue_unref_and_unlock     (GAsyncQueue      *queue); +#endif /* !G_DISABLE_DEPRECATED */ + +/* Push data into the async queue. Must not be NULL. */ +void         g_async_queue_push                 (GAsyncQueue      *queue, +						 gpointer          data); +void         g_async_queue_push_unlocked        (GAsyncQueue      *queue, +						 gpointer          data); + +void         g_async_queue_push_sorted          (GAsyncQueue      *queue, +						 gpointer          data, +						 GCompareDataFunc  func, +						 gpointer          user_data); +void         g_async_queue_push_sorted_unlocked (GAsyncQueue      *queue, +						 gpointer          data, +						 GCompareDataFunc  func, +						 gpointer          user_data); + +/* Pop data from the async queue. When no data is there, the thread is blocked + * until data arrives. + */ +gpointer     g_async_queue_pop                  (GAsyncQueue      *queue); +gpointer     g_async_queue_pop_unlocked         (GAsyncQueue      *queue); + +/* Try to pop data. NULL is returned in case of empty queue. */ +gpointer     g_async_queue_try_pop              (GAsyncQueue      *queue); +gpointer     g_async_queue_try_pop_unlocked     (GAsyncQueue      *queue); + + + +/* Wait for data until at maximum until end_time is reached. NULL is returned + * in case of empty queue.  + */ +gpointer     g_async_queue_timed_pop            (GAsyncQueue      *queue, +						 GTimeVal         *end_time); +gpointer     g_async_queue_timed_pop_unlocked   (GAsyncQueue      *queue, +						 GTimeVal         *end_time); + +/* Return the length of the queue. Negative values mean that threads + * are waiting, positve values mean that there are entries in the + * queue. Actually this function returns the length of the queue minus + * the number of waiting threads, g_async_queue_length == 0 could also + * mean 'n' entries in the queue and 'n' thread waiting. Such can + * happen due to locking of the queue or due to scheduling.  + */ +gint         g_async_queue_length               (GAsyncQueue      *queue); +gint         g_async_queue_length_unlocked      (GAsyncQueue      *queue); +void         g_async_queue_sort                 (GAsyncQueue      *queue, +						 GCompareDataFunc  func, +						 gpointer          user_data); +void         g_async_queue_sort_unlocked        (GAsyncQueue      *queue, +						 GCompareDataFunc  func, +						 gpointer          user_data); + +/* Private API */ +GMutex*      _g_async_queue_get_mutex           (GAsyncQueue      *queue); + +G_END_DECLS + +#endif /* __G_ASYNCQUEUE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gatomic.h b/protocols/Sametime/src/glib/include/glib/gatomic.h new file mode 100644 index 0000000000..ddd39b8a3a --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gatomic.h @@ -0,0 +1,105 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * g_atomic_*: atomic operations. + * Copyright (C) 2003 Sebastian Wilhelmi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_ATOMIC_H__ +#define __G_ATOMIC_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +gint     g_atomic_int_exchange_and_add         (volatile gint G_GNUC_MAY_ALIAS *atomic, +						gint      	   val); +void     g_atomic_int_add                      (volatile gint G_GNUC_MAY_ALIAS *atomic, +						gint      	   val); +gboolean g_atomic_int_compare_and_exchange     (volatile gint G_GNUC_MAY_ALIAS *atomic, +						gint      	   oldval, +						gint      	   newval); +gboolean g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic,  +						gpointer  	   oldval,  +						gpointer  	   newval); + +gint     g_atomic_int_get                      (volatile gint G_GNUC_MAY_ALIAS *atomic); +void     g_atomic_int_set                      (volatile gint G_GNUC_MAY_ALIAS *atomic, +						gint               newval); +gpointer g_atomic_pointer_get                  (volatile gpointer G_GNUC_MAY_ALIAS *atomic); +void     g_atomic_pointer_set                  (volatile gpointer G_GNUC_MAY_ALIAS *atomic, +						gpointer           newval); + +#ifndef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED +# define g_atomic_int_get(atomic) 		((gint)*(atomic)) +# define g_atomic_int_set(atomic, newval) 	((void) (*(atomic) = (newval))) +# define g_atomic_pointer_get(atomic) 		((gpointer)*(atomic)) +# define g_atomic_pointer_set(atomic, newval)	((void) (*(atomic) = (newval))) +#else +# define g_atomic_int_get(atomic) \ + ((void) sizeof (gchar [sizeof (*(atomic)) == sizeof (gint) ? 1 : -1]), \ +  (g_atomic_int_get) ((volatile gint G_GNUC_MAY_ALIAS *) (volatile void *) (atomic))) +# define g_atomic_int_set(atomic, newval) \ + ((void) sizeof (gchar [sizeof (*(atomic)) == sizeof (gint) ? 1 : -1]), \ +  (g_atomic_int_set) ((volatile gint G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval))) +# define g_atomic_pointer_get(atomic) \ + ((void) sizeof (gchar [sizeof (*(atomic)) == sizeof (gpointer) ? 1 : -1]), \ +  (g_atomic_pointer_get) ((volatile gpointer G_GNUC_MAY_ALIAS *) (volatile void *) (atomic))) +# define g_atomic_pointer_set(atomic, newval) \ + ((void) sizeof (gchar [sizeof (*(atomic)) == sizeof (gpointer) ? 1 : -1]), \ +  (g_atomic_pointer_set) ((volatile gpointer G_GNUC_MAY_ALIAS *) (volatile void *) (atomic), (newval))) +#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ + +/** + * g_atomic_int_inc: + * @atomic: a pointer to an integer. + * + * Atomically increments the integer pointed to by @atomic by 1. + * + * Since: 2.4 + */ +#define g_atomic_int_inc(atomic) (g_atomic_int_add ((atomic), 1)) + +/** + * g_atomic_int_dec_and_test: + * @atomic: a pointer to an integer + * + * Atomically decrements the integer pointed to by @atomic by 1. + * + * Returns: %TRUE if the integer pointed to by @atomic is 0 + *     after decrementing it + * + * Since: 2.4 + */ +#define g_atomic_int_dec_and_test(atomic) \ +  (g_atomic_int_exchange_and_add ((atomic), -1) == 1) + +G_END_DECLS + +#endif /* __G_ATOMIC_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gbacktrace.h b/protocols/Sametime/src/glib/include/glib/gbacktrace.h new file mode 100644 index 0000000000..43a0c46a21 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gbacktrace.h @@ -0,0 +1,68 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_BACKTRACE_H__ +#define __G_BACKTRACE_H__ + +#include <glib/gtypes.h> +#include <signal.h> + +G_BEGIN_DECLS + +/* Fatal error handlers. + * g_on_error_query() will prompt the user to either + * [E]xit, [H]alt, [P]roceed or show [S]tack trace. + * g_on_error_stack_trace() invokes gdb, which attaches to the current + * process and shows a stack trace. + * These function may cause different actions on non-unix platforms. + * The prg_name arg is required by gdb to find the executable, if it is + * passed as NULL, g_on_error_query() will try g_get_prgname(). + */ +void g_on_error_query (const gchar *prg_name); +void g_on_error_stack_trace (const gchar *prg_name); + +/* Hacker macro to place breakpoints for selected machines. + * Actual use is strongly discouraged of course ;) + */ +#if (defined (__i386__) || defined (__x86_64__)) && defined (__GNUC__) && __GNUC__ >= 2 +#  define G_BREAKPOINT()        G_STMT_START{ __asm__ __volatile__ ("int $03"); }G_STMT_END +#elif (defined (_MSC_VER) || defined (__DMC__)) && defined (_M_IX86) +#  define G_BREAKPOINT()        G_STMT_START{ __asm int 3h }G_STMT_END +#elif defined (_MSC_VER) +#  define G_BREAKPOINT()        G_STMT_START{ __debugbreak(); }G_STMT_END +#elif defined (__alpha__) && !defined(__osf__) && defined (__GNUC__) && __GNUC__ >= 2 +#  define G_BREAKPOINT()        G_STMT_START{ __asm__ __volatile__ ("bpt"); }G_STMT_END +#else   /* !__i386__ && !__alpha__ */ +#  define G_BREAKPOINT()        G_STMT_START{ raise (SIGTRAP); }G_STMT_END +#endif  /* __i386__ */ + +G_END_DECLS + +#endif /* __G_BACKTRACE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gbase64.h b/protocols/Sametime/src/glib/include/glib/gbase64.h new file mode 100644 index 0000000000..930389a674 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gbase64.h @@ -0,0 +1,57 @@ +/* gbase64.h - Base64 coding functions + * + *  Copyright (C) 2005  Alexander Larsson <alexl@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_BASE64_H__ +#define __G_BASE64_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +gsize   g_base64_encode_step    (const guchar *in, +                                 gsize         len, +                                 gboolean      break_lines, +                                 gchar        *out, +                                 gint         *state, +                                 gint         *save); +gsize   g_base64_encode_close   (gboolean      break_lines, +                                 gchar        *out, +                                 gint         *state, +                                 gint         *save); +gchar*  g_base64_encode         (const guchar *data, +                                 gsize         len) G_GNUC_MALLOC; +gsize   g_base64_decode_step    (const gchar  *in, +                                 gsize         len, +                                 guchar       *out, +                                 gint         *state, +                                 guint        *save); +guchar *g_base64_decode         (const gchar  *text, +                                 gsize        *out_len) G_GNUC_MALLOC; +guchar *g_base64_decode_inplace (gchar        *text, +                                 gsize        *out_len); + + +G_END_DECLS + +#endif /* __G_BASE64_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gbitlock.h b/protocols/Sametime/src/glib/include/glib/gbitlock.h new file mode 100644 index 0000000000..5f6a67fd84 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gbitlock.h @@ -0,0 +1,43 @@ +/* + * Copyright © 2008 Ryan Lortie + * Copyright © 2010 Codethink Limited + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Ryan Lortie <desrt@desrt.ca> + */ + +#ifndef __G_BITLOCK_H__ +#define __G_BITLOCK_H__ + +#include <glib/gtypes.h> + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +G_BEGIN_DECLS + +void      g_bit_lock                      (volatile gint *address, +                                           gint           lock_bit); +gboolean  g_bit_trylock                   (volatile gint *address, +                                           gint           lock_bit); +void      g_bit_unlock                    (volatile gint *address, +                                           gint           lock_bit); + +G_END_DECLS + +#endif /* __G_BITLOCK_H_ */ diff --git a/protocols/Sametime/src/glib/include/glib/gbookmarkfile.h b/protocols/Sametime/src/glib/include/glib/gbookmarkfile.h new file mode 100644 index 0000000000..f663ebf27f --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gbookmarkfile.h @@ -0,0 +1,215 @@ +/* gbookmarkfile.h: parsing and building desktop bookmarks + * + * Copyright (C) 2005-2006 Emmanuele Bassi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_BOOKMARK_FILE_H__ +#define __G_BOOKMARK_FILE_H__ + +#include <glib/gerror.h> +#include <time.h> + +G_BEGIN_DECLS + +/** + * G_BOOKMARK_FILE_ERROR: + * + * Error domain for bookmark file parsing. + * Errors in this domain will be from the #GBookmarkFileError + * enumeration. See #GError for information on error domains. + */ +#define G_BOOKMARK_FILE_ERROR	(g_bookmark_file_error_quark ()) + + +/** + * GBookmarkFileError: + * @G_BOOKMARK_FILE_ERROR_INVALID_URI: URI was ill-formed + * @G_BOOKMARK_FILE_ERROR_INVALID_VALUE: a requested field was not found + * @G_BOOKMARK_FILE_ERROR_APP_NOT_REGISTERED: a requested application did + *     not register a bookmark + * @G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND: a requested URI was not found + * @G_BOOKMARK_FILE_ERROR_READ: document was ill formed + * @G_BOOKMARK_FILE_ERROR_UNKNOWN_ENCODING: the text being parsed was + *     in an unknown encoding + * @G_BOOKMARK_FILE_ERROR_WRITE: an error occurred while writing + * @G_BOOKMARK_FILE_ERROR_FILE_NOT_FOUND: requested file was not found + * + * Error codes returned by bookmark file parsing. + */ +typedef enum +{ +  G_BOOKMARK_FILE_ERROR_INVALID_URI, +  G_BOOKMARK_FILE_ERROR_INVALID_VALUE, +  G_BOOKMARK_FILE_ERROR_APP_NOT_REGISTERED, +  G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND, +  G_BOOKMARK_FILE_ERROR_READ, +  G_BOOKMARK_FILE_ERROR_UNKNOWN_ENCODING, +  G_BOOKMARK_FILE_ERROR_WRITE, +  G_BOOKMARK_FILE_ERROR_FILE_NOT_FOUND +} GBookmarkFileError; + +GQuark g_bookmark_file_error_quark (void); + +/** + * GBookmarkFile: + * + * The <structname>GBookmarkFile</structname> struct contains only + * private data and should not be directly accessed. + */ +typedef struct _GBookmarkFile GBookmarkFile; + +GBookmarkFile *g_bookmark_file_new                 (void); +void           g_bookmark_file_free                (GBookmarkFile  *bookmark); + +gboolean       g_bookmark_file_load_from_file      (GBookmarkFile  *bookmark, +						    const gchar    *filename, +						    GError        **error); +gboolean       g_bookmark_file_load_from_data      (GBookmarkFile  *bookmark, +						    const gchar    *data, +						    gsize           length, +						    GError        **error); +gboolean       g_bookmark_file_load_from_data_dirs (GBookmarkFile  *bookmark, +						    const gchar    *file, +						    gchar         **full_path, +						    GError        **error); +gchar *        g_bookmark_file_to_data             (GBookmarkFile  *bookmark, +						    gsize          *length, +						    GError        **error) G_GNUC_MALLOC; +gboolean       g_bookmark_file_to_file             (GBookmarkFile  *bookmark, +						    const gchar    *filename, +						    GError        **error); + +void           g_bookmark_file_set_title           (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar    *title); +gchar *        g_bookmark_file_get_title           (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    GError        **error) G_GNUC_MALLOC; +void           g_bookmark_file_set_description     (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar    *description); +gchar *        g_bookmark_file_get_description     (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    GError        **error) G_GNUC_MALLOC; +void           g_bookmark_file_set_mime_type       (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar    *mime_type); +gchar *        g_bookmark_file_get_mime_type       (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    GError        **error) G_GNUC_MALLOC; +void           g_bookmark_file_set_groups          (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar   **groups, +						    gsize           length); +void           g_bookmark_file_add_group           (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar    *group); +gboolean       g_bookmark_file_has_group           (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar    *group, +						    GError        **error); +gchar **       g_bookmark_file_get_groups          (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    gsize          *length, +						    GError        **error) G_GNUC_MALLOC; +void           g_bookmark_file_add_application     (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar    *name, +						    const gchar    *exec); +gboolean       g_bookmark_file_has_application     (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar    *name, +						    GError        **error); +gchar **       g_bookmark_file_get_applications    (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    gsize          *length, +						    GError        **error) G_GNUC_MALLOC; +gboolean       g_bookmark_file_set_app_info        (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar    *name, +						    const gchar    *exec, +						    gint            count, +						    time_t          stamp, +						    GError        **error); +gboolean       g_bookmark_file_get_app_info        (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar    *name, +						    gchar         **exec, +						    guint          *count, +						    time_t         *stamp, +						    GError        **error); +void           g_bookmark_file_set_is_private      (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    gboolean        is_private); +gboolean       g_bookmark_file_get_is_private      (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    GError        **error); +void           g_bookmark_file_set_icon            (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar    *href, +						    const gchar    *mime_type); +gboolean       g_bookmark_file_get_icon            (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    gchar         **href, +						    gchar         **mime_type, +						    GError        **error); +void           g_bookmark_file_set_added           (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    time_t          added); +time_t         g_bookmark_file_get_added           (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    GError        **error); +void           g_bookmark_file_set_modified        (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    time_t          modified); +time_t         g_bookmark_file_get_modified        (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    GError        **error); +void           g_bookmark_file_set_visited         (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    time_t          visited); +time_t         g_bookmark_file_get_visited         (GBookmarkFile  *bookmark, +						    const gchar    *uri,  +						    GError        **error); +gboolean       g_bookmark_file_has_item            (GBookmarkFile  *bookmark, +						    const gchar    *uri); +gint           g_bookmark_file_get_size            (GBookmarkFile  *bookmark); +gchar **       g_bookmark_file_get_uris            (GBookmarkFile  *bookmark, +						    gsize          *length) G_GNUC_MALLOC; +gboolean       g_bookmark_file_remove_group        (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar    *group, +						    GError        **error); +gboolean       g_bookmark_file_remove_application  (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    const gchar    *name, +						    GError        **error); +gboolean       g_bookmark_file_remove_item         (GBookmarkFile  *bookmark, +						    const gchar    *uri, +						    GError        **error); +gboolean       g_bookmark_file_move_item           (GBookmarkFile  *bookmark, +						    const gchar    *old_uri, +						    const gchar    *new_uri, +						    GError        **error); + +G_END_DECLS + +#endif /* __G_BOOKMARK_FILE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gcache.h b/protocols/Sametime/src/glib/include/glib/gcache.h new file mode 100644 index 0000000000..7d60d5888c --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gcache.h @@ -0,0 +1,69 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_CACHE_H__ +#define __G_CACHE_H__ + +#include <glib/glist.h> + +G_BEGIN_DECLS + +typedef struct _GCache          GCache; + +typedef gpointer        (*GCacheNewFunc)        (gpointer       key); +typedef gpointer        (*GCacheDupFunc)        (gpointer       value); +typedef void            (*GCacheDestroyFunc)    (gpointer       value); + +/* Caches + */ +GCache*  g_cache_new           (GCacheNewFunc      value_new_func, +                                GCacheDestroyFunc  value_destroy_func, +                                GCacheDupFunc      key_dup_func, +                                GCacheDestroyFunc  key_destroy_func, +                                GHashFunc          hash_key_func, +                                GHashFunc          hash_value_func, +                                GEqualFunc         key_equal_func); +void     g_cache_destroy       (GCache            *cache); +gpointer g_cache_insert        (GCache            *cache, +                                gpointer           key); +void     g_cache_remove        (GCache            *cache, +                                gconstpointer      value); +void     g_cache_key_foreach   (GCache            *cache, +                                GHFunc             func, +                                gpointer           user_data); +#ifndef G_DISABLE_DEPRECATED +void     g_cache_value_foreach (GCache            *cache, +                                GHFunc             func, +                                gpointer           user_data); +#endif + +G_END_DECLS + +#endif /* __G_CACHE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gchecksum.h b/protocols/Sametime/src/glib/include/glib/gchecksum.h new file mode 100644 index 0000000000..57aea103f7 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gchecksum.h @@ -0,0 +1,86 @@ +/* gchecksum.h - data hashing functions + * + * Copyright (C) 2007  Emmanuele Bassi  <ebassi@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_CHECKSUM_H__ +#define __G_CHECKSUM_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +/** + * GChecksumType: + * @G_CHECKSUM_MD5: Use the MD5 hashing algorithm + * @G_CHECKSUM_SHA1: Use the SHA-1 hashing algorithm + * @G_CHECKSUM_SHA256: Use the SHA-256 hashing algorithm + * + * The hashing algorithm to be used by #GChecksum when performing the + * digest of some data. + * + * Note that the #GChecksumType enumeration may be extended at a later + * date to include new hashing algorithm types. + * + * Since: 2.16 + */ +typedef enum { +  G_CHECKSUM_MD5, +  G_CHECKSUM_SHA1, +  G_CHECKSUM_SHA256 +} GChecksumType; + +/** + * GChecksum: + * + * An opaque structure representing a checksumming operation. + * To create a new GChecksum, use g_checksum_new(). To free + * a GChecksum, use g_checksum_free(). + * + * Since: 2.16 + */ +typedef struct _GChecksum       GChecksum; + +gssize                g_checksum_type_get_length    (GChecksumType    checksum_type); + +GChecksum *           g_checksum_new                (GChecksumType    checksum_type); +void                  g_checksum_reset              (GChecksum       *checksum); +GChecksum *           g_checksum_copy               (const GChecksum *checksum); +void                  g_checksum_free               (GChecksum       *checksum); +void                  g_checksum_update             (GChecksum       *checksum, +                                                     const guchar    *data, +                                                     gssize           length); +G_CONST_RETURN gchar *g_checksum_get_string         (GChecksum       *checksum); +void                  g_checksum_get_digest         (GChecksum       *checksum, +                                                     guint8          *buffer, +                                                     gsize           *digest_len); + +gchar                *g_compute_checksum_for_data   (GChecksumType    checksum_type, +                                                     const guchar    *data, +                                                     gsize            length); +gchar                *g_compute_checksum_for_string (GChecksumType    checksum_type, +                                                     const gchar     *str, +                                                     gssize           length); + +G_END_DECLS + +#endif /* __G_CHECKSUM_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gcompletion.h b/protocols/Sametime/src/glib/include/glib/gcompletion.h new file mode 100644 index 0000000000..04c024fc5a --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gcompletion.h @@ -0,0 +1,81 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_COMPLETION_H__ +#define __G_COMPLETION_H__ + +#include <glib/glist.h> + +G_BEGIN_DECLS + +typedef struct _GCompletion     GCompletion; + +typedef gchar*          (*GCompletionFunc)      (gpointer); + +/* GCompletion + */ + +typedef gint (*GCompletionStrncmpFunc) (const gchar *s1, +					const gchar *s2, +					gsize        n); + +struct _GCompletion +{ +  GList* items; +  GCompletionFunc func; +  +  gchar* prefix; +  GList* cache; +  GCompletionStrncmpFunc strncmp_func; +}; + +#ifndef G_DISABLE_DEPRECATED + +GCompletion* g_completion_new           (GCompletionFunc func); +void         g_completion_add_items     (GCompletion*    cmp, +                                         GList*          items); +void         g_completion_remove_items  (GCompletion*    cmp, +                                         GList*          items); +void         g_completion_clear_items   (GCompletion*    cmp); +GList*       g_completion_complete      (GCompletion*    cmp, +                                         const gchar*    prefix, +                                         gchar**         new_prefix); +GList*       g_completion_complete_utf8 (GCompletion  *cmp, +                                         const gchar*    prefix, +                                         gchar**         new_prefix); +void         g_completion_set_compare   (GCompletion *cmp, +				         GCompletionStrncmpFunc strncmp_func); +void         g_completion_free          (GCompletion*    cmp); + +#endif + +G_END_DECLS + +#endif /* __G_COMPLETION_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gconvert.h b/protocols/Sametime/src/glib/include/glib/gconvert.h new file mode 100644 index 0000000000..e4c20d77d5 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gconvert.h @@ -0,0 +1,162 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_CONVERT_H__ +#define __G_CONVERT_H__ + +#include <glib/gerror.h> + +G_BEGIN_DECLS + +/** + * GConvertError: + * @G_CONVERT_ERROR_NO_CONVERSION: Conversion between the requested character + *     sets is not supported. + * @G_CONVERT_ERROR_ILLEGAL_SEQUENCE: Invalid byte sequence in conversion input. + * @G_CONVERT_ERROR_FAILED: Conversion failed for some reason. + * @G_CONVERT_ERROR_PARTIAL_INPUT: Partial character sequence at end of input. + * @G_CONVERT_ERROR_BAD_URI: URI is invalid. + * @G_CONVERT_ERROR_NOT_ABSOLUTE_PATH: Pathname is not an absolute path. + * + * Error codes returned by character set conversion routines. + */ +typedef enum +{ +  G_CONVERT_ERROR_NO_CONVERSION, +  G_CONVERT_ERROR_ILLEGAL_SEQUENCE, +  G_CONVERT_ERROR_FAILED, +  G_CONVERT_ERROR_PARTIAL_INPUT, +  G_CONVERT_ERROR_BAD_URI, +  G_CONVERT_ERROR_NOT_ABSOLUTE_PATH +} GConvertError; + +/** + * G_CONVERT_ERROR: + * + * Error domain for character set conversions. Errors in this domain will + * be from the #GConvertError enumeration. See #GError for information on + * error domains. + */ +#define G_CONVERT_ERROR g_convert_error_quark() +GQuark g_convert_error_quark (void); + +/** + * GIconv: + * + * The <structname>GIConv</structname> struct wraps an + * iconv() conversion descriptor. It contains private data + * and should only be accessed using the following functions. + */ +typedef struct _GIConv *GIConv; + +GIConv g_iconv_open   (const gchar  *to_codeset, +		       const gchar  *from_codeset); +gsize  g_iconv        (GIConv        converter, +		       gchar       **inbuf, +		       gsize        *inbytes_left, +		       gchar       **outbuf, +		       gsize        *outbytes_left); +gint   g_iconv_close  (GIConv        converter); + + +gchar* g_convert               (const gchar  *str, +				gssize        len,             +				const gchar  *to_codeset, +				const gchar  *from_codeset, +				gsize        *bytes_read,      +				gsize        *bytes_written,   +				GError      **error) G_GNUC_MALLOC; +gchar* g_convert_with_iconv    (const gchar  *str, +				gssize        len, +				GIConv        converter, +				gsize        *bytes_read,      +				gsize        *bytes_written,   +				GError      **error) G_GNUC_MALLOC; +gchar* g_convert_with_fallback (const gchar  *str, +				gssize        len,             +				const gchar  *to_codeset, +				const gchar  *from_codeset, +				const gchar  *fallback, +				gsize        *bytes_read,      +				gsize        *bytes_written,   +				GError      **error) G_GNUC_MALLOC; + + +/* Convert between libc's idea of strings and UTF-8. + */ +gchar* g_locale_to_utf8   (const gchar  *opsysstring, +			   gssize        len,             +			   gsize        *bytes_read,      +			   gsize        *bytes_written,   +			   GError      **error) G_GNUC_MALLOC; +gchar* g_locale_from_utf8 (const gchar  *utf8string, +			   gssize        len,             +			   gsize        *bytes_read,      +			   gsize        *bytes_written,   +			   GError      **error) G_GNUC_MALLOC; + +/* Convert between the operating system (or C runtime) + * representation of file names and UTF-8. + */ +#ifdef G_OS_WIN32 +#define g_filename_to_utf8 g_filename_to_utf8_utf8 +#define g_filename_from_utf8 g_filename_from_utf8_utf8 +#define g_filename_from_uri g_filename_from_uri_utf8 +#define g_filename_to_uri g_filename_to_uri_utf8  +#endif + +gchar* g_filename_to_utf8   (const gchar  *opsysstring, +			     gssize        len,             +			     gsize        *bytes_read,      +			     gsize        *bytes_written,   +			     GError      **error) G_GNUC_MALLOC; +gchar* g_filename_from_utf8 (const gchar  *utf8string, +			     gssize        len,             +			     gsize        *bytes_read,      +			     gsize        *bytes_written,   +			     GError      **error) G_GNUC_MALLOC; + +gchar *g_filename_from_uri (const gchar *uri, +			    gchar      **hostname, +			    GError     **error) G_GNUC_MALLOC; +   +gchar *g_filename_to_uri   (const gchar *filename, +			    const gchar *hostname, +			    GError     **error) G_GNUC_MALLOC; +gchar *g_filename_display_name (const gchar *filename) G_GNUC_MALLOC; +gboolean g_get_filename_charsets (G_CONST_RETURN gchar ***charsets); + +gchar *g_filename_display_basename (const gchar *filename) G_GNUC_MALLOC; + +gchar **g_uri_list_extract_uris (const gchar *uri_list) G_GNUC_MALLOC; + +G_END_DECLS + +#endif /* __G_CONVERT_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gdataset.h b/protocols/Sametime/src/glib/include/glib/gdataset.h new file mode 100644 index 0000000000..2733ffb033 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gdataset.h @@ -0,0 +1,122 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_DATASET_H__ +#define __G_DATASET_H__ + +#include <glib/gquark.h> + +G_BEGIN_DECLS + +typedef struct _GData           GData; + +typedef void            (*GDataForeachFunc)     (GQuark         key_id, +                                                 gpointer       data, +                                                 gpointer       user_data); + +/* Keyed Data List + */ +void     g_datalist_init                (GData            **datalist); +void     g_datalist_clear               (GData            **datalist); +gpointer g_datalist_id_get_data         (GData            **datalist, +					 GQuark             key_id); +void     g_datalist_id_set_data_full    (GData            **datalist, +					 GQuark             key_id, +					 gpointer           data, +					 GDestroyNotify     destroy_func); +gpointer g_datalist_id_remove_no_notify (GData            **datalist, +					 GQuark             key_id); +void     g_datalist_foreach             (GData            **datalist, +					 GDataForeachFunc   func, +					 gpointer           user_data); + +/** + * G_DATALIST_FLAGS_MASK: + * + * A bitmask that restricts the possible flags passed to + * g_datalist_set_flags(). Passing a flags value where + * flags & ~G_DATALIST_FLAGS_MASK != 0 is an error. + */ +#define G_DATALIST_FLAGS_MASK 0x3 + +void     g_datalist_set_flags           (GData            **datalist, +					 guint              flags); +void     g_datalist_unset_flags         (GData            **datalist, +					 guint              flags); +guint    g_datalist_get_flags           (GData            **datalist); + +#define   g_datalist_id_set_data(dl, q, d)      \ +     g_datalist_id_set_data_full ((dl), (q), (d), NULL) +#define   g_datalist_id_remove_data(dl, q)      \ +     g_datalist_id_set_data ((dl), (q), NULL) +#define   g_datalist_get_data(dl, k)            \ +     (g_datalist_id_get_data ((dl), g_quark_try_string (k))) +#define   g_datalist_set_data_full(dl, k, d, f) \ +     g_datalist_id_set_data_full ((dl), g_quark_from_string (k), (d), (f)) +#define   g_datalist_remove_no_notify(dl, k)    \ +     g_datalist_id_remove_no_notify ((dl), g_quark_try_string (k)) +#define   g_datalist_set_data(dl, k, d)         \ +     g_datalist_set_data_full ((dl), (k), (d), NULL) +#define   g_datalist_remove_data(dl, k)         \ +     g_datalist_id_set_data ((dl), g_quark_try_string (k), NULL) + + +/* Location Associated Keyed Data + */ +void      g_dataset_destroy             (gconstpointer    dataset_location); +gpointer  g_dataset_id_get_data         (gconstpointer    dataset_location, +                                         GQuark           key_id); +void      g_dataset_id_set_data_full    (gconstpointer    dataset_location, +                                         GQuark           key_id, +                                         gpointer         data, +                                         GDestroyNotify   destroy_func); +gpointer  g_dataset_id_remove_no_notify (gconstpointer    dataset_location, +                                         GQuark           key_id); +void      g_dataset_foreach             (gconstpointer    dataset_location, +                                         GDataForeachFunc func, +                                         gpointer         user_data); +#define   g_dataset_id_set_data(l, k, d)        \ +     g_dataset_id_set_data_full ((l), (k), (d), NULL) +#define   g_dataset_id_remove_data(l, k)        \ +     g_dataset_id_set_data ((l), (k), NULL) +#define   g_dataset_get_data(l, k)              \ +     (g_dataset_id_get_data ((l), g_quark_try_string (k))) +#define   g_dataset_set_data_full(l, k, d, f)   \ +     g_dataset_id_set_data_full ((l), g_quark_from_string (k), (d), (f)) +#define   g_dataset_remove_no_notify(l, k)      \ +     g_dataset_id_remove_no_notify ((l), g_quark_try_string (k)) +#define   g_dataset_set_data(l, k, d)           \ +     g_dataset_set_data_full ((l), (k), (d), NULL) +#define   g_dataset_remove_data(l, k)           \ +     g_dataset_id_set_data ((l), g_quark_try_string (k), NULL) + +G_END_DECLS + +#endif /* __G_DATASET_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gdate.h b/protocols/Sametime/src/glib/include/glib/gdate.h new file mode 100644 index 0000000000..cb1f566155 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gdate.h @@ -0,0 +1,263 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_DATE_H__ +#define __G_DATE_H__ + +#include <time.h> + +#include <glib/gtypes.h> +#include <glib/gquark.h> + +G_BEGIN_DECLS + +/* GDate + * + * Date calculations (not time for now, to be resolved). These are a + * mutant combination of Steffen Beyer's DateCalc routines + * (http://www.perl.com/CPAN/authors/id/STBEY/) and Jon Trowbridge's + * date routines (written for in-house software).  Written by Havoc + * Pennington <hp@pobox.com> + */ + +typedef gint32  GTime; +typedef guint16 GDateYear; +typedef guint8  GDateDay;   /* day of the month */ +typedef struct _GDate GDate; + +/* enum used to specify order of appearance in parsed date strings */ +typedef enum +{ +  G_DATE_DAY   = 0, +  G_DATE_MONTH = 1, +  G_DATE_YEAR  = 2 +} GDateDMY; + +/* actual week and month values */ +typedef enum +{ +  G_DATE_BAD_WEEKDAY  = 0, +  G_DATE_MONDAY       = 1, +  G_DATE_TUESDAY      = 2, +  G_DATE_WEDNESDAY    = 3, +  G_DATE_THURSDAY     = 4, +  G_DATE_FRIDAY       = 5, +  G_DATE_SATURDAY     = 6, +  G_DATE_SUNDAY       = 7 +} GDateWeekday; +typedef enum +{ +  G_DATE_BAD_MONTH = 0, +  G_DATE_JANUARY   = 1, +  G_DATE_FEBRUARY  = 2, +  G_DATE_MARCH     = 3, +  G_DATE_APRIL     = 4, +  G_DATE_MAY       = 5, +  G_DATE_JUNE      = 6, +  G_DATE_JULY      = 7, +  G_DATE_AUGUST    = 8, +  G_DATE_SEPTEMBER = 9, +  G_DATE_OCTOBER   = 10, +  G_DATE_NOVEMBER  = 11, +  G_DATE_DECEMBER  = 12 +} GDateMonth; + +#define G_DATE_BAD_JULIAN 0U +#define G_DATE_BAD_DAY    0U +#define G_DATE_BAD_YEAR   0U + +/* Note: directly manipulating structs is generally a bad idea, but + * in this case it's an *incredibly* bad idea, because all or part + * of this struct can be invalid at any given time. Use the functions, + * or you will get hosed, I promise. + */ +struct _GDate +{ +  guint julian_days : 32; /* julian days representation - we use a +                           *  bitfield hoping that 64 bit platforms +                           *  will pack this whole struct in one big +                           *  int +                           */ + +  guint julian : 1;    /* julian is valid */ +  guint dmy    : 1;    /* dmy is valid */ + +  /* DMY representation */ +  guint day    : 6; +  guint month  : 4; +  guint year   : 16; +}; + +/* g_date_new() returns an invalid date, you then have to _set() stuff + * to get a usable object. You can also allocate a GDate statically, + * then call g_date_clear() to initialize. + */ +GDate*       g_date_new                   (void); +GDate*       g_date_new_dmy               (GDateDay     day, +                                           GDateMonth   month, +                                           GDateYear    year); +GDate*       g_date_new_julian            (guint32      julian_day); +void         g_date_free                  (GDate       *date); + +/* check g_date_valid() after doing an operation that might fail, like + * _parse.  Almost all g_date operations are undefined on invalid + * dates (the exceptions are the mutators, since you need those to + * return to validity). + */ +gboolean     g_date_valid                 (const GDate *date); +gboolean     g_date_valid_day             (GDateDay     day) G_GNUC_CONST; +gboolean     g_date_valid_month           (GDateMonth month) G_GNUC_CONST; +gboolean     g_date_valid_year            (GDateYear  year) G_GNUC_CONST; +gboolean     g_date_valid_weekday         (GDateWeekday weekday) G_GNUC_CONST; +gboolean     g_date_valid_julian          (guint32 julian_date) G_GNUC_CONST; +gboolean     g_date_valid_dmy             (GDateDay     day, +                                           GDateMonth   month, +                                           GDateYear    year) G_GNUC_CONST; + +GDateWeekday g_date_get_weekday           (const GDate *date); +GDateMonth   g_date_get_month             (const GDate *date); +GDateYear    g_date_get_year              (const GDate *date); +GDateDay     g_date_get_day               (const GDate *date); +guint32      g_date_get_julian            (const GDate *date); +guint        g_date_get_day_of_year       (const GDate *date); +/* First monday/sunday is the start of week 1; if we haven't reached + * that day, return 0. These are not ISO weeks of the year; that + * routine needs to be added. + * these functions return the number of weeks, starting on the + * corrsponding day + */ +guint        g_date_get_monday_week_of_year (const GDate *date); +guint        g_date_get_sunday_week_of_year (const GDate *date); +guint        g_date_get_iso8601_week_of_year (const GDate *date); + +/* If you create a static date struct you need to clear it to get it + * in a sane state before use. You can clear a whole array at + * once with the ndates argument. + */ +void         g_date_clear                 (GDate       *date, +                                           guint        n_dates); + +/* The parse routine is meant for dates typed in by a user, so it + * permits many formats but tries to catch common typos. If your data + * needs to be strictly validated, it is not an appropriate function. + */ +void         g_date_set_parse             (GDate       *date, +                                           const gchar *str); +void         g_date_set_time_t            (GDate       *date, +					   time_t       timet); +void         g_date_set_time_val          (GDate       *date, +					   GTimeVal    *timeval); +#ifndef G_DISABLE_DEPRECATED +void         g_date_set_time              (GDate       *date, +                                           GTime        time_); +#endif +void         g_date_set_month             (GDate       *date, +                                           GDateMonth   month); +void         g_date_set_day               (GDate       *date, +                                           GDateDay     day); +void         g_date_set_year              (GDate       *date, +                                           GDateYear    year); +void         g_date_set_dmy               (GDate       *date, +                                           GDateDay     day, +                                           GDateMonth   month, +                                           GDateYear    y); +void         g_date_set_julian            (GDate       *date, +                                           guint32      julian_date); +gboolean     g_date_is_first_of_month     (const GDate *date); +gboolean     g_date_is_last_of_month      (const GDate *date); + +/* To go forward by some number of weeks just go forward weeks*7 days */ +void         g_date_add_days              (GDate       *date, +                                           guint        n_days); +void         g_date_subtract_days         (GDate       *date, +                                           guint        n_days); + +/* If you add/sub months while day > 28, the day might change */ +void         g_date_add_months            (GDate       *date, +                                           guint        n_months); +void         g_date_subtract_months       (GDate       *date, +                                           guint        n_months); + +/* If it's feb 29, changing years can move you to the 28th */ +void         g_date_add_years             (GDate       *date, +                                           guint        n_years); +void         g_date_subtract_years        (GDate       *date, +                                           guint        n_years); +gboolean     g_date_is_leap_year          (GDateYear    year) G_GNUC_CONST; +guint8       g_date_get_days_in_month     (GDateMonth   month, +                                           GDateYear    year) G_GNUC_CONST; +guint8       g_date_get_monday_weeks_in_year  (GDateYear    year) G_GNUC_CONST; +guint8       g_date_get_sunday_weeks_in_year  (GDateYear    year) G_GNUC_CONST; + +/* Returns the number of days between the two dates.  If date2 comes +   before date1, a negative value is return. */ +gint         g_date_days_between          (const GDate *date1, +					   const GDate *date2); + +/* qsort-friendly (with a cast...) */ +gint         g_date_compare               (const GDate *lhs, +                                           const GDate *rhs); +void         g_date_to_struct_tm          (const GDate *date, +                                           struct tm   *tm); + +void         g_date_clamp                 (GDate *date, +					   const GDate *min_date, +					   const GDate *max_date); + +/* Swap date1 and date2's values if date1 > date2. */ +void         g_date_order                 (GDate *date1, GDate *date2); + +/* Just like strftime() except you can only use date-related formats. + *   Using a time format is undefined. + */ +gsize        g_date_strftime              (gchar       *s, +                                           gsize        slen, +                                           const gchar *format, +                                           const GDate *date); + +#ifndef G_DISABLE_DEPRECATED + +#define g_date_weekday 			g_date_get_weekday +#define g_date_month 			g_date_get_month +#define g_date_year 			g_date_get_year +#define g_date_day 			g_date_get_day +#define g_date_julian 			g_date_get_julian +#define g_date_day_of_year 		g_date_get_day_of_year +#define g_date_monday_week_of_year 	g_date_get_monday_week_of_year +#define g_date_sunday_week_of_year 	g_date_get_sunday_week_of_year +#define g_date_days_in_month 		g_date_get_days_in_month +#define g_date_monday_weeks_in_year 	g_date_get_monday_weeks_in_year +#define g_date_sunday_weeks_in_year	g_date_get_sunday_weeks_in_year + +#endif /* G_DISABLE_DEPRECATED */ + +G_END_DECLS + +#endif /* __G_DATE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gdatetime.h b/protocols/Sametime/src/glib/include/glib/gdatetime.h new file mode 100644 index 0000000000..b76df89c7e --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gdatetime.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2009-2010 Christian Hergert <chris@dronelabs.com> + * Copyright © 2010 Codethink Limited + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * licence, or (at your option) any later version. + * + * This is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 + * USA. + * + * Authors: Christian Hergert <chris@dronelabs.com> + *          Thiago Santos <thiago.sousa.santos@collabora.co.uk> + *          Emmanuele Bassi <ebassi@linux.intel.com> + *          Ryan Lortie <desrt@desrt.ca> + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_DATE_TIME_H__ +#define __G_DATE_TIME_H__ + +#include <glib/gtimezone.h> + +G_BEGIN_DECLS + +/** + * G_TIME_SPAN_DAY: + * + * Evaluates to a time span of one day. + * + * Since: 2.26 + */ +#define G_TIME_SPAN_DAY                 (G_GINT64_CONSTANT (86400000000)) + +/** + * G_TIME_SPAN_HOUR: + * + * Evaluates to a time span of one hour. + * + * Since: 2.26 + */ +#define G_TIME_SPAN_HOUR                (G_GINT64_CONSTANT (3600000000)) + +/** + * G_TIME_SPAN_MINUTE: + * + * Evaluates to a time span of one minute. + * + * Since: 2.26 + */ +#define G_TIME_SPAN_MINUTE              (G_GINT64_CONSTANT (60000000)) + +/** + * G_TIME_SPAN_SECOND: + * + * Evaluates to a time span of one second. + * + * Since: 2.26 + */ +#define G_TIME_SPAN_SECOND              (G_GINT64_CONSTANT (1000000)) + +/** + * G_TIME_SPAN_MILLISECOND: + * + * Evaluates to a time span of one millisecond. + * + * Since: 2.26 + */ +#define G_TIME_SPAN_MILLISECOND         (G_GINT64_CONSTANT (1000)) + +/** + * GTimeSpan: + * + * A value representing an interval of time, in microseconds. + * + * Since: 2.26 + */ +typedef gint64 GTimeSpan; + +/** + * GDateTime: + * + * <structname>GDateTime</structname> is an opaque structure whose members + * cannot be accessed directly. + * + * Since: 2.26 + */ +typedef struct _GDateTime GDateTime; + +void                    g_date_time_unref                               (GDateTime      *datetime); +GDateTime *             g_date_time_ref                                 (GDateTime      *datetime); + +GDateTime *             g_date_time_new_now                             (GTimeZone      *tz); +GDateTime *             g_date_time_new_now_local                       (void); +GDateTime *             g_date_time_new_now_utc                         (void); + +GDateTime *             g_date_time_new_from_unix_local                 (gint64          t); +GDateTime *             g_date_time_new_from_unix_utc                   (gint64          t); + +GDateTime *             g_date_time_new_from_timeval_local              (const GTimeVal *tv); +GDateTime *             g_date_time_new_from_timeval_utc                (const GTimeVal *tv); + +GDateTime *             g_date_time_new                                 (GTimeZone      *tz, +                                                                         gint            year, +                                                                         gint            month, +                                                                         gint            day, +                                                                         gint            hour, +                                                                         gint            minute, +                                                                         gdouble         seconds); +GDateTime *             g_date_time_new_local                           (gint            year, +                                                                         gint            month, +                                                                         gint            day, +                                                                         gint            hour, +                                                                         gint            minute, +                                                                         gdouble         seconds); +GDateTime *             g_date_time_new_utc                             (gint            year, +                                                                         gint            month, +                                                                         gint            day, +                                                                         gint            hour, +                                                                         gint            minute, +                                                                         gdouble         seconds); + +G_GNUC_WARN_UNUSED_RESULT +GDateTime *             g_date_time_add                                 (GDateTime      *datetime, +                                                                         GTimeSpan       timespan); + +G_GNUC_WARN_UNUSED_RESULT +GDateTime *             g_date_time_add_years                           (GDateTime      *datetime, +                                                                         gint            years); +G_GNUC_WARN_UNUSED_RESULT +GDateTime *             g_date_time_add_months                          (GDateTime      *datetime, +                                                                         gint            months); +G_GNUC_WARN_UNUSED_RESULT +GDateTime *             g_date_time_add_weeks                           (GDateTime      *datetime, +                                                                         gint            weeks); +G_GNUC_WARN_UNUSED_RESULT +GDateTime *             g_date_time_add_days                            (GDateTime      *datetime, +                                                                         gint            days); + +G_GNUC_WARN_UNUSED_RESULT +GDateTime *             g_date_time_add_hours                           (GDateTime      *datetime, +                                                                         gint            hours); +G_GNUC_WARN_UNUSED_RESULT +GDateTime *             g_date_time_add_minutes                         (GDateTime      *datetime, +                                                                         gint            minutes); +G_GNUC_WARN_UNUSED_RESULT +GDateTime *             g_date_time_add_seconds                         (GDateTime      *datetime, +                                                                         gdouble         seconds); + +G_GNUC_WARN_UNUSED_RESULT +GDateTime *             g_date_time_add_full                            (GDateTime      *datetime, +                                                                         gint            years, +                                                                         gint            months, +                                                                         gint            days, +                                                                         gint            hours, +                                                                         gint            minutes, +                                                                         gdouble         seconds); + +gint                    g_date_time_compare                             (gconstpointer   dt1, +                                                                         gconstpointer   dt2); +GTimeSpan               g_date_time_difference                          (GDateTime      *end, +                                                                         GDateTime      *begin); +guint                   g_date_time_hash                                (gconstpointer   datetime); +gboolean                g_date_time_equal                               (gconstpointer   dt1, +                                                                         gconstpointer   dt2); + +void                    g_date_time_get_ymd                             (GDateTime      *datetime, +                                                                         gint           *year, +                                                                         gint           *month, +                                                                         gint           *day); + +gint                    g_date_time_get_year                            (GDateTime      *datetime); +gint                    g_date_time_get_month                           (GDateTime      *datetime); +gint                    g_date_time_get_day_of_month                    (GDateTime      *datetime); + +gint                    g_date_time_get_week_numbering_year             (GDateTime      *datetime); +gint                    g_date_time_get_week_of_year                    (GDateTime      *datetime); +gint                    g_date_time_get_day_of_week                     (GDateTime      *datetime); + +gint                    g_date_time_get_day_of_year                     (GDateTime      *datetime); + +gint                    g_date_time_get_hour                            (GDateTime      *datetime); +gint                    g_date_time_get_minute                          (GDateTime      *datetime); +gint                    g_date_time_get_second                          (GDateTime      *datetime); +gint                    g_date_time_get_microsecond                     (GDateTime      *datetime); +gdouble                 g_date_time_get_seconds                         (GDateTime      *datetime); + +gint64                  g_date_time_to_unix                             (GDateTime      *datetime); +gboolean                g_date_time_to_timeval                          (GDateTime      *datetime, +                                                                         GTimeVal       *tv); + +GTimeSpan               g_date_time_get_utc_offset                      (GDateTime      *datetime); +const gchar *           g_date_time_get_timezone_abbreviation           (GDateTime      *datetime); +gboolean                g_date_time_is_daylight_savings                 (GDateTime      *datetime); + +GDateTime *             g_date_time_to_timezone                         (GDateTime      *datetime, +                                                                         GTimeZone      *tz); +GDateTime *             g_date_time_to_local                            (GDateTime      *datetime); +GDateTime *             g_date_time_to_utc                              (GDateTime      *datetime); + +gchar *                 g_date_time_format                              (GDateTime      *datetime, +                                                                         const gchar    *format) G_GNUC_MALLOC; + +G_END_DECLS + +#endif /* __G_DATE_TIME_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gdir.h b/protocols/Sametime/src/glib/include/glib/gdir.h new file mode 100644 index 0000000000..85e989695a --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gdir.h @@ -0,0 +1,52 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * gdir.c: Simplified wrapper around the DIRENT functions. + * + * Copyright 2001 Hans Breuer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_DIR_H__ +#define __G_DIR_H__ + +#include <glib/gerror.h> + +G_BEGIN_DECLS + +typedef struct _GDir GDir; + +#ifdef G_OS_WIN32 +/* For DLL ABI stability, keep old names for old (non-UTF-8) functionality. */ +#define g_dir_open g_dir_open_utf8 +#define g_dir_read_name g_dir_read_name_utf8 +#endif + +GDir    *                g_dir_open           (const gchar  *path, +					       guint         flags, +					       GError      **error); +G_CONST_RETURN gchar    *g_dir_read_name      (GDir         *dir); +void                     g_dir_rewind         (GDir         *dir); +void                     g_dir_close          (GDir         *dir); + +G_END_DECLS + +#endif /* __G_DIR_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gerror.h b/protocols/Sametime/src/glib/include/glib/gerror.h new file mode 100644 index 0000000000..b303487782 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gerror.h @@ -0,0 +1,98 @@ +/* gerror.h - Error reporting system + * + *  Copyright 2000 Red Hat, Inc. + * + * The Gnome Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Gnome Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the Gnome Library; see the file COPYING.LIB.  If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + *   Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_ERROR_H__ +#define __G_ERROR_H__ + +#include <stdarg.h> + +#include <glib/gquark.h> + +G_BEGIN_DECLS + +typedef struct _GError GError; + +struct _GError +{ +  GQuark       domain; +  gint         code; +  gchar       *message; +}; + +GError*  g_error_new           (GQuark         domain, +                                gint           code, +                                const gchar   *format, +                                ...) G_GNUC_PRINTF (3, 4); + +GError*  g_error_new_literal   (GQuark         domain, +                                gint           code, +                                const gchar   *message); +GError*  g_error_new_valist    (GQuark         domain, +                                gint           code, +                                const gchar   *format, +                                va_list        args); + +void     g_error_free          (GError        *error); +GError*  g_error_copy          (const GError  *error); + +gboolean g_error_matches       (const GError  *error, +                                GQuark         domain, +                                gint           code); + +/* if (err) *err = g_error_new(domain, code, format, ...), also has + * some sanity checks. + */ +void     g_set_error           (GError       **err, +                                GQuark         domain, +                                gint           code, +                                const gchar   *format, +                                ...) G_GNUC_PRINTF (4, 5); + +void     g_set_error_literal   (GError       **err, +                                GQuark         domain, +                                gint           code, +                                const gchar   *message); + +/* if (dest) *dest = src; also has some sanity checks. + */ +void     g_propagate_error     (GError       **dest, +				GError        *src); + +/* if (err && *err) { g_error_free(*err); *err = NULL; } */ +void     g_clear_error         (GError       **err); + +/* if (err) prefix the formatted string to the ->message */ +void     g_prefix_error               (GError       **err, +                                       const gchar   *format, +                                       ...) G_GNUC_PRINTF (2, 3); + +/* g_propagate_error then g_error_prefix on dest */ +void     g_propagate_prefixed_error   (GError       **dest, +                                       GError        *src, +                                       const gchar   *format, +                                       ...) G_GNUC_PRINTF (3, 4); + +G_END_DECLS + +#endif /* __G_ERROR_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gfileutils.h b/protocols/Sametime/src/glib/include/glib/gfileutils.h new file mode 100644 index 0000000000..d8f9d3bea1 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gfileutils.h @@ -0,0 +1,128 @@ +/* gfileutils.h - File utility functions + * + *  Copyright 2000 Red Hat, Inc. + * + * GLib is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * GLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with GLib; see the file COPYING.LIB.  If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + *   Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_FILEUTILS_H__ +#define __G_FILEUTILS_H__ + +#include <glib/gerror.h> + +G_BEGIN_DECLS + +#define G_FILE_ERROR g_file_error_quark () + +typedef enum +{ +  G_FILE_ERROR_EXIST, +  G_FILE_ERROR_ISDIR, +  G_FILE_ERROR_ACCES, +  G_FILE_ERROR_NAMETOOLONG, +  G_FILE_ERROR_NOENT, +  G_FILE_ERROR_NOTDIR, +  G_FILE_ERROR_NXIO, +  G_FILE_ERROR_NODEV, +  G_FILE_ERROR_ROFS, +  G_FILE_ERROR_TXTBSY, +  G_FILE_ERROR_FAULT, +  G_FILE_ERROR_LOOP, +  G_FILE_ERROR_NOSPC, +  G_FILE_ERROR_NOMEM, +  G_FILE_ERROR_MFILE, +  G_FILE_ERROR_NFILE, +  G_FILE_ERROR_BADF, +  G_FILE_ERROR_INVAL, +  G_FILE_ERROR_PIPE, +  G_FILE_ERROR_AGAIN, +  G_FILE_ERROR_INTR, +  G_FILE_ERROR_IO, +  G_FILE_ERROR_PERM, +  G_FILE_ERROR_NOSYS, +  G_FILE_ERROR_FAILED +} GFileError; + +/* For backward-compat reasons, these are synced to an old  + * anonymous enum in libgnome. But don't use that enum + * in new code. + */ +typedef enum +{ +  G_FILE_TEST_IS_REGULAR    = 1 << 0, +  G_FILE_TEST_IS_SYMLINK    = 1 << 1, +  G_FILE_TEST_IS_DIR        = 1 << 2, +  G_FILE_TEST_IS_EXECUTABLE = 1 << 3, +  G_FILE_TEST_EXISTS        = 1 << 4 +} GFileTest; + +GQuark     g_file_error_quark      (void); +/* So other code can generate a GFileError */ +GFileError g_file_error_from_errno (gint err_no); + +#ifdef G_OS_WIN32 +#define g_file_test g_file_test_utf8 +#define g_file_get_contents g_file_get_contents_utf8 +#define g_mkstemp g_mkstemp_utf8 +#define g_file_open_tmp g_file_open_tmp_utf8 +#endif + +gboolean g_file_test         (const gchar  *filename, +                              GFileTest     test); +gboolean g_file_get_contents (const gchar  *filename, +                              gchar       **contents, +                              gsize        *length,     +                              GError      **error); +gboolean g_file_set_contents (const gchar *filename, +			      const gchar *contents, +			      gssize	     length, +			      GError	   **error); +gchar   *g_file_read_link    (const gchar  *filename, +			      GError      **error); + +/* Wrapper / workalike for mkstemp() */ +gint    g_mkstemp            (gchar        *tmpl); +gint    g_mkstemp_full       (gchar        *tmpl, +                              int           flags, +                              int           mode); + +/* Wrapper for g_mkstemp */ +gint    g_file_open_tmp      (const gchar  *tmpl, +			      gchar       **name_used, +			      GError      **error); + +char *g_format_size_for_display (goffset size); + +gchar *g_build_path     (const gchar *separator, +			 const gchar *first_element, +			 ...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED; +gchar *g_build_pathv    (const gchar  *separator, +			 gchar       **args) G_GNUC_MALLOC; + +gchar *g_build_filename (const gchar *first_element, +			 ...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED; +gchar *g_build_filenamev (gchar      **args) G_GNUC_MALLOC; + +int    g_mkdir_with_parents (const gchar *pathname, +			     int          mode); + +G_END_DECLS + +#endif /* __G_FILEUTILS_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/ghash.h b/protocols/Sametime/src/glib/include/glib/ghash.h new file mode 100644 index 0000000000..9128721bcf --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/ghash.h @@ -0,0 +1,166 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_HASH_H__ +#define __G_HASH_H__ + +#include <glib/gtypes.h> +#include <glib/glist.h> + +G_BEGIN_DECLS + +typedef struct _GHashTable  GHashTable; + +typedef gboolean  (*GHRFunc)  (gpointer  key, +                               gpointer  value, +                               gpointer  user_data); + +typedef struct _GHashTableIter GHashTableIter; + +struct _GHashTableIter +{ +  /*< private >*/ +  gpointer	dummy1; +  gpointer	dummy2; +  gpointer	dummy3; +  int		dummy4; +  gboolean	dummy5; +  gpointer	dummy6; +}; + +/* Hash tables + */ +GHashTable* g_hash_table_new		   (GHashFunc	    hash_func, +					    GEqualFunc	    key_equal_func); +GHashTable* g_hash_table_new_full      	   (GHashFunc	    hash_func, +					    GEqualFunc	    key_equal_func, +					    GDestroyNotify  key_destroy_func, +					    GDestroyNotify  value_destroy_func); +void	    g_hash_table_destroy	   (GHashTable	   *hash_table); +void	    g_hash_table_insert		   (GHashTable	   *hash_table, +					    gpointer	    key, +					    gpointer	    value); +void        g_hash_table_replace           (GHashTable     *hash_table, +					    gpointer	    key, +					    gpointer	    value); +gboolean    g_hash_table_remove		   (GHashTable	   *hash_table, +					    gconstpointer   key); +void        g_hash_table_remove_all        (GHashTable     *hash_table); +gboolean    g_hash_table_steal             (GHashTable     *hash_table, +					    gconstpointer   key); +void        g_hash_table_steal_all         (GHashTable     *hash_table); +gpointer    g_hash_table_lookup		   (GHashTable	   *hash_table, +					    gconstpointer   key); +gboolean    g_hash_table_lookup_extended   (GHashTable	   *hash_table, +					    gconstpointer   lookup_key, +					    gpointer	   *orig_key, +					    gpointer	   *value); +void	    g_hash_table_foreach	   (GHashTable	   *hash_table, +					    GHFunc	    func, +					    gpointer	    user_data); +gpointer    g_hash_table_find	           (GHashTable	   *hash_table, +					    GHRFunc	    predicate, +					    gpointer	    user_data); +guint	    g_hash_table_foreach_remove	   (GHashTable	   *hash_table, +					    GHRFunc	    func, +					    gpointer	    user_data); +guint	    g_hash_table_foreach_steal	   (GHashTable	   *hash_table, +					    GHRFunc	    func, +					    gpointer	    user_data); +guint	    g_hash_table_size		   (GHashTable	   *hash_table); +GList *     g_hash_table_get_keys          (GHashTable     *hash_table); +GList *     g_hash_table_get_values        (GHashTable     *hash_table); + +void        g_hash_table_iter_init         (GHashTableIter *iter, +					    GHashTable     *hash_table); +gboolean    g_hash_table_iter_next         (GHashTableIter *iter, +					    gpointer       *key, +					    gpointer       *value); +GHashTable* g_hash_table_iter_get_hash_table (GHashTableIter *iter); +void        g_hash_table_iter_remove       (GHashTableIter *iter); +void        g_hash_table_iter_steal        (GHashTableIter *iter); + +/* keeping hash tables alive */ +GHashTable* g_hash_table_ref   		   (GHashTable 	   *hash_table); +void        g_hash_table_unref             (GHashTable     *hash_table); + +#ifndef G_DISABLE_DEPRECATED + +/** + * g_hash_table_freeze: + * @hash_table: a #GHashTable + * + * This function is deprecated and will be removed in the next major + * release of GLib. It does nothing. + **/ +#define g_hash_table_freeze(hash_table) ((void)0) + +/** + * g_hash_table_thaw: + * @hash_table: a #GHashTable + * + * This function is deprecated and will be removed in the next major + * release of GLib. It does nothing. + **/ +#define g_hash_table_thaw(hash_table) ((void)0) + +#endif /* G_DISABLE_DEPRECATED */ + +/* Hash Functions + */ +gboolean g_str_equal (gconstpointer  v1, +                      gconstpointer  v2); +guint    g_str_hash  (gconstpointer  v); + +gboolean g_int_equal (gconstpointer  v1, +                      gconstpointer  v2); +guint    g_int_hash  (gconstpointer  v); + +gboolean g_int64_equal (gconstpointer  v1, +                        gconstpointer  v2); +guint    g_int64_hash  (gconstpointer  v); + +gboolean g_double_equal (gconstpointer  v1, +                         gconstpointer  v2); +guint    g_double_hash  (gconstpointer  v); + +/* This "hash" function will just return the key's address as an + * unsigned integer. Useful for hashing on plain addresses or + * simple integer values. + * Passing NULL into g_hash_table_new() as GHashFunc has the + * same effect as passing g_direct_hash(). + */ +guint    g_direct_hash  (gconstpointer  v) G_GNUC_CONST; +gboolean g_direct_equal (gconstpointer  v1, +                         gconstpointer  v2) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __G_HASH_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/ghook.h b/protocols/Sametime/src/glib/include/glib/ghook.h new file mode 100644 index 0000000000..5577fc3e21 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/ghook.h @@ -0,0 +1,181 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_HOOK_H__ +#define __G_HOOK_H__ + +#include <glib/gmem.h> + +G_BEGIN_DECLS + + +/* --- typedefs --- */ +typedef struct _GHook		GHook; +typedef struct _GHookList	GHookList; + +typedef gint		(*GHookCompareFunc)	(GHook		*new_hook, +						 GHook		*sibling); +typedef gboolean	(*GHookFindFunc)	(GHook		*hook, +						 gpointer	 data); +typedef void		(*GHookMarshaller)	(GHook		*hook, +						 gpointer	 marshal_data); +typedef gboolean	(*GHookCheckMarshaller)	(GHook		*hook, +						 gpointer	 marshal_data); +typedef void		(*GHookFunc)		(gpointer	 data); +typedef gboolean	(*GHookCheckFunc)	(gpointer	 data); +typedef void		(*GHookFinalizeFunc)	(GHookList      *hook_list, +						 GHook          *hook); +typedef enum +{ +  G_HOOK_FLAG_ACTIVE	    = 1 << 0, +  G_HOOK_FLAG_IN_CALL	    = 1 << 1, +  G_HOOK_FLAG_MASK	    = 0x0f +} GHookFlagMask; +#define G_HOOK_FLAG_USER_SHIFT	(4) + + +/* --- structures --- */ +struct _GHookList +{ +  gulong	    seq_id; +  guint		    hook_size : 16; +  guint		    is_setup : 1; +  GHook		   *hooks; +  gpointer	    dummy3; +  GHookFinalizeFunc finalize_hook; +  gpointer	    dummy[2]; +}; +struct _GHook +{ +  gpointer	 data; +  GHook		*next; +  GHook		*prev; +  guint		 ref_count; +  gulong	 hook_id; +  guint		 flags; +  gpointer	 func; +  GDestroyNotify destroy; +}; + + +/* --- macros --- */ +#define	G_HOOK(hook)			((GHook*) (hook)) +#define	G_HOOK_FLAGS(hook)		(G_HOOK (hook)->flags) +#define	G_HOOK_ACTIVE(hook)		((G_HOOK_FLAGS (hook) & \ +					  G_HOOK_FLAG_ACTIVE) != 0) +#define	G_HOOK_IN_CALL(hook)		((G_HOOK_FLAGS (hook) & \ +					  G_HOOK_FLAG_IN_CALL) != 0) +#define G_HOOK_IS_VALID(hook)		(G_HOOK (hook)->hook_id != 0 && \ +					 (G_HOOK_FLAGS (hook) & \ +                                          G_HOOK_FLAG_ACTIVE)) +#define G_HOOK_IS_UNLINKED(hook)	(G_HOOK (hook)->next == NULL && \ +					 G_HOOK (hook)->prev == NULL && \ +					 G_HOOK (hook)->hook_id == 0 && \ +					 G_HOOK (hook)->ref_count == 0) + + +/* --- prototypes --- */ +/* callback maintenance functions */ +void	 g_hook_list_init		(GHookList		*hook_list, +					 guint			 hook_size); +void	 g_hook_list_clear		(GHookList		*hook_list); +GHook*	 g_hook_alloc			(GHookList		*hook_list); +void	 g_hook_free			(GHookList		*hook_list, +					 GHook			*hook); +GHook *	 g_hook_ref			(GHookList		*hook_list, +					 GHook			*hook); +void	 g_hook_unref			(GHookList		*hook_list, +					 GHook			*hook); +gboolean g_hook_destroy			(GHookList		*hook_list, +					 gulong			 hook_id); +void	 g_hook_destroy_link		(GHookList		*hook_list, +					 GHook			*hook); +void	 g_hook_prepend			(GHookList		*hook_list, +					 GHook			*hook); +void	 g_hook_insert_before		(GHookList		*hook_list, +					 GHook			*sibling, +					 GHook			*hook); +void	 g_hook_insert_sorted		(GHookList		*hook_list, +					 GHook			*hook, +					 GHookCompareFunc	 func); +GHook*	 g_hook_get			(GHookList		*hook_list, +					 gulong			 hook_id); +GHook*	 g_hook_find			(GHookList		*hook_list, +					 gboolean		 need_valids, +					 GHookFindFunc		 func, +					 gpointer		 data); +GHook*	 g_hook_find_data		(GHookList		*hook_list, +					 gboolean		 need_valids, +					 gpointer		 data); +GHook*	 g_hook_find_func		(GHookList		*hook_list, +					 gboolean		 need_valids, +					 gpointer		 func); +GHook*	 g_hook_find_func_data		(GHookList		*hook_list, +					 gboolean		 need_valids, +					 gpointer		 func, +					 gpointer		 data); +/* return the first valid hook, and increment its reference count */ +GHook*	 g_hook_first_valid		(GHookList		*hook_list, +					 gboolean		 may_be_in_call); +/* return the next valid hook with incremented reference count, and + * decrement the reference count of the original hook + */ +GHook*	 g_hook_next_valid		(GHookList		*hook_list, +					 GHook			*hook, +					 gboolean		 may_be_in_call); +/* GHookCompareFunc implementation to insert hooks sorted by their id */ +gint	 g_hook_compare_ids		(GHook			*new_hook, +					 GHook			*sibling); +/* convenience macros */ +#define	 g_hook_append( hook_list, hook )  \ +     g_hook_insert_before ((hook_list), NULL, (hook)) +/* invoke all valid hooks with the (*GHookFunc) signature. + */ +void	 g_hook_list_invoke		(GHookList		*hook_list, +					 gboolean		 may_recurse); +/* invoke all valid hooks with the (*GHookCheckFunc) signature, + * and destroy the hook if FALSE is returned. + */ +void	 g_hook_list_invoke_check	(GHookList		*hook_list, +					 gboolean		 may_recurse); +/* invoke a marshaller on all valid hooks. + */ +void	 g_hook_list_marshal		(GHookList		*hook_list, +					 gboolean		 may_recurse, +					 GHookMarshaller	 marshaller, +					 gpointer		 marshal_data); +void	 g_hook_list_marshal_check	(GHookList		*hook_list, +					 gboolean		 may_recurse, +					 GHookCheckMarshaller	 marshaller, +					 gpointer		 marshal_data); + +G_END_DECLS + +#endif /* __G_HOOK_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/ghostutils.h b/protocols/Sametime/src/glib/include/glib/ghostutils.h new file mode 100644 index 0000000000..0349da364b --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/ghostutils.h @@ -0,0 +1,40 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_HOST_UTILS_H__ +#define __G_HOST_UTILS_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +gboolean  g_hostname_is_non_ascii     (const gchar *hostname); +gboolean  g_hostname_is_ascii_encoded (const gchar *hostname); +gboolean  g_hostname_is_ip_address    (const gchar *hostname); + +gchar    *g_hostname_to_ascii         (const gchar *hostname); +gchar    *g_hostname_to_unicode       (const gchar *hostname); + +G_END_DECLS + +#endif /* __G_HOST_UTILS_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/giochannel.h b/protocols/Sametime/src/glib/include/glib/giochannel.h new file mode 100644 index 0000000000..2a40aa29ae --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/giochannel.h @@ -0,0 +1,366 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_IOCHANNEL_H__ +#define __G_IOCHANNEL_H__ + +#include <glib/gconvert.h> +#include <glib/gmain.h> +#include <glib/gstring.h> + +G_BEGIN_DECLS + +/* GIOChannel + */ + +typedef struct _GIOChannel	GIOChannel; +typedef struct _GIOFuncs        GIOFuncs; + +typedef enum +{ +  G_IO_ERROR_NONE, +  G_IO_ERROR_AGAIN, +  G_IO_ERROR_INVAL, +  G_IO_ERROR_UNKNOWN +} GIOError; + +#define G_IO_CHANNEL_ERROR g_io_channel_error_quark() + +typedef enum +{ +  /* Derived from errno */ +  G_IO_CHANNEL_ERROR_FBIG, +  G_IO_CHANNEL_ERROR_INVAL, +  G_IO_CHANNEL_ERROR_IO, +  G_IO_CHANNEL_ERROR_ISDIR, +  G_IO_CHANNEL_ERROR_NOSPC, +  G_IO_CHANNEL_ERROR_NXIO, +  G_IO_CHANNEL_ERROR_OVERFLOW, +  G_IO_CHANNEL_ERROR_PIPE, +  /* Other */ +  G_IO_CHANNEL_ERROR_FAILED +} GIOChannelError; + +typedef enum +{ +  G_IO_STATUS_ERROR, +  G_IO_STATUS_NORMAL, +  G_IO_STATUS_EOF, +  G_IO_STATUS_AGAIN +} GIOStatus; + +typedef enum +{ +  G_SEEK_CUR, +  G_SEEK_SET, +  G_SEEK_END +} GSeekType; + +typedef enum +{ +  G_IO_IN	GLIB_SYSDEF_POLLIN, +  G_IO_OUT	GLIB_SYSDEF_POLLOUT, +  G_IO_PRI	GLIB_SYSDEF_POLLPRI, +  G_IO_ERR	GLIB_SYSDEF_POLLERR, +  G_IO_HUP	GLIB_SYSDEF_POLLHUP, +  G_IO_NVAL	GLIB_SYSDEF_POLLNVAL +} GIOCondition; + +typedef enum +{ +  G_IO_FLAG_APPEND = 1 << 0, +  G_IO_FLAG_NONBLOCK = 1 << 1, +  G_IO_FLAG_IS_READABLE = 1 << 2,	/* Read only flag */ +  G_IO_FLAG_IS_WRITEABLE = 1 << 3,	/* Read only flag */ +  G_IO_FLAG_IS_SEEKABLE = 1 << 4,	/* Read only flag */ +  G_IO_FLAG_MASK = (1 << 5) - 1, +  G_IO_FLAG_GET_MASK = G_IO_FLAG_MASK, +  G_IO_FLAG_SET_MASK = G_IO_FLAG_APPEND | G_IO_FLAG_NONBLOCK +} GIOFlags; + +struct _GIOChannel +{ +  /*< private >*/ +  gint ref_count; +  GIOFuncs *funcs; + +  gchar *encoding; +  GIConv read_cd; +  GIConv write_cd; +  gchar *line_term;		/* String which indicates the end of a line of text */ +  guint line_term_len;		/* So we can have null in the line term */ + +  gsize buf_size; +  GString *read_buf;		/* Raw data from the channel */ +  GString *encoded_read_buf;    /* Channel data converted to UTF-8 */ +  GString *write_buf;		/* Data ready to be written to the file */ +  gchar partial_write_buf[6];	/* UTF-8 partial characters, null terminated */ + +  /* Group the flags together, immediately after partial_write_buf, to save memory */ + +  guint use_buffer     : 1;	/* The encoding uses the buffers */ +  guint do_encode      : 1;	/* The encoding uses the GIConv coverters */ +  guint close_on_unref : 1;	/* Close the channel on final unref */ +  guint is_readable    : 1;	/* Cached GIOFlag */ +  guint is_writeable   : 1;	/* ditto */ +  guint is_seekable    : 1;	/* ditto */ + +  gpointer reserved1;	 +  gpointer reserved2;	 +}; + +typedef gboolean (*GIOFunc) (GIOChannel   *source, +			     GIOCondition  condition, +			     gpointer      data); +struct _GIOFuncs +{ +  GIOStatus (*io_read)           (GIOChannel   *channel,  +			          gchar        *buf,  +				  gsize         count, +				  gsize        *bytes_read, +				  GError      **err); +  GIOStatus (*io_write)          (GIOChannel   *channel,  +				  const gchar  *buf,  +				  gsize         count, +				  gsize        *bytes_written, +				  GError      **err); +  GIOStatus (*io_seek)           (GIOChannel   *channel,  +				  gint64        offset,  +				  GSeekType     type, +				  GError      **err); +  GIOStatus  (*io_close)         (GIOChannel   *channel, +				  GError      **err); +  GSource*   (*io_create_watch)  (GIOChannel   *channel, +				  GIOCondition  condition); +  void       (*io_free)          (GIOChannel   *channel); +  GIOStatus  (*io_set_flags)     (GIOChannel   *channel, +                                  GIOFlags      flags, +				  GError      **err); +  GIOFlags   (*io_get_flags)     (GIOChannel   *channel); +}; + +void        g_io_channel_init   (GIOChannel    *channel); +GIOChannel *g_io_channel_ref    (GIOChannel    *channel); +void        g_io_channel_unref  (GIOChannel    *channel); + +#ifndef G_DISABLE_DEPRECATED +GIOError    g_io_channel_read   (GIOChannel    *channel,  +			         gchar         *buf,  +			         gsize          count, +			         gsize         *bytes_read); +GIOError  g_io_channel_write    (GIOChannel    *channel,  +			         const gchar   *buf,  +			         gsize          count, +			         gsize         *bytes_written); +GIOError  g_io_channel_seek     (GIOChannel    *channel, +			         gint64         offset,  +			         GSeekType      type); +void      g_io_channel_close    (GIOChannel    *channel); +#endif /* G_DISABLE_DEPRECATED */ + +GIOStatus g_io_channel_shutdown (GIOChannel      *channel, +				 gboolean         flush, +				 GError         **err); +guint     g_io_add_watch_full   (GIOChannel      *channel, +				 gint             priority, +				 GIOCondition     condition, +				 GIOFunc          func, +				 gpointer         user_data, +				 GDestroyNotify   notify); +GSource * g_io_create_watch     (GIOChannel      *channel, +				 GIOCondition     condition); +guint     g_io_add_watch        (GIOChannel      *channel, +				 GIOCondition     condition, +				 GIOFunc          func, +				 gpointer         user_data); + +/* character encoding conversion involved functions. + */ + +void                  g_io_channel_set_buffer_size      (GIOChannel   *channel, +							 gsize         size); +gsize                 g_io_channel_get_buffer_size      (GIOChannel   *channel); +GIOCondition          g_io_channel_get_buffer_condition (GIOChannel   *channel); +GIOStatus             g_io_channel_set_flags            (GIOChannel   *channel, +							 GIOFlags      flags, +							 GError      **error); +GIOFlags              g_io_channel_get_flags            (GIOChannel   *channel); +void                  g_io_channel_set_line_term        (GIOChannel   *channel, +							 const gchar  *line_term, +							 gint          length); +G_CONST_RETURN gchar* g_io_channel_get_line_term        (GIOChannel   *channel, +							 gint         *length); +void		      g_io_channel_set_buffered		(GIOChannel   *channel, +							 gboolean      buffered); +gboolean	      g_io_channel_get_buffered		(GIOChannel   *channel); +GIOStatus             g_io_channel_set_encoding         (GIOChannel   *channel, +							 const gchar  *encoding, +							 GError      **error); +G_CONST_RETURN gchar* g_io_channel_get_encoding         (GIOChannel   *channel); +void                  g_io_channel_set_close_on_unref	(GIOChannel   *channel, +							 gboolean      do_close); +gboolean              g_io_channel_get_close_on_unref	(GIOChannel   *channel); + + +GIOStatus   g_io_channel_flush            (GIOChannel   *channel, +					   GError      **error); +GIOStatus   g_io_channel_read_line        (GIOChannel   *channel, +					   gchar       **str_return, +					   gsize        *length, +					   gsize        *terminator_pos, +					   GError      **error); +GIOStatus   g_io_channel_read_line_string (GIOChannel   *channel, +					   GString      *buffer, +					   gsize        *terminator_pos, +					   GError      **error); +GIOStatus   g_io_channel_read_to_end      (GIOChannel   *channel, +					   gchar       **str_return, +					   gsize        *length, +					   GError      **error); +GIOStatus   g_io_channel_read_chars       (GIOChannel   *channel, +					   gchar        *buf, +					   gsize         count, +					   gsize        *bytes_read, +					   GError      **error); +GIOStatus   g_io_channel_read_unichar     (GIOChannel   *channel, +					   gunichar     *thechar, +					   GError      **error); +GIOStatus   g_io_channel_write_chars      (GIOChannel   *channel, +					   const gchar  *buf, +					   gssize        count, +					   gsize        *bytes_written, +					   GError      **error); +GIOStatus   g_io_channel_write_unichar    (GIOChannel   *channel, +					   gunichar      thechar, +					   GError      **error); +GIOStatus   g_io_channel_seek_position    (GIOChannel   *channel, +					   gint64        offset, +					   GSeekType     type, +					   GError      **error); +#ifdef G_OS_WIN32 +#define g_io_channel_new_file g_io_channel_new_file_utf8 +#endif + +GIOChannel* g_io_channel_new_file         (const gchar  *filename, +					   const gchar  *mode, +					   GError      **error); + +/* Error handling */ + +GQuark          g_io_channel_error_quark      (void); +GIOChannelError g_io_channel_error_from_errno (gint en); + +/* On Unix, IO channels created with this function for any file + * descriptor or socket. + * + * On Win32, this can be used either for files opened with the MSVCRT + * (the Microsoft run-time C library) _open() or _pipe, including file + * descriptors 0, 1 and 2 (corresponding to stdin, stdout and stderr), + * or for Winsock SOCKETs. If the parameter is a legal file + * descriptor, it is assumed to be such, otherwise it should be a + * SOCKET. This relies on SOCKETs and file descriptors not + * overlapping. If you want to be certain, call either + * g_io_channel_win32_new_fd() or g_io_channel_win32_new_socket() + * instead as appropriate. + * + * The term file descriptor as used in the context of Win32 refers to + * the emulated Unix-like file descriptors MSVCRT provides. The native + * corresponding concept is file HANDLE. There isn't as of yet a way to + * get GIOChannels for Win32 file HANDLEs. + */ +GIOChannel* g_io_channel_unix_new    (int         fd); +gint        g_io_channel_unix_get_fd (GIOChannel *channel); + + +/* Hook for GClosure / GSource integration. Don't touch */ +GLIB_VAR GSourceFuncs g_io_watch_funcs; + +#ifdef G_OS_WIN32 + +/* You can use this "pseudo file descriptor" in a GPollFD to add + * polling for Windows messages. GTK applications should not do that. + */ + +#define G_WIN32_MSG_HANDLE 19981206 + +/* Use this to get a GPollFD from a GIOChannel, so that you can call + * g_io_channel_win32_poll(). After calling this you should only use + * g_io_channel_read() to read from the GIOChannel, i.e. never read() + * from the underlying file descriptor. For SOCKETs, it is possible to call + * recv(). + */ +void        g_io_channel_win32_make_pollfd (GIOChannel   *channel, +					    GIOCondition  condition, +					    GPollFD      *fd); + +/* This can be used to wait a until at least one of the channels is readable. + * On Unix you would do a select() on the file descriptors of the channels. + */ +gint        g_io_channel_win32_poll   (GPollFD    *fds, +				       gint        n_fds, +				       gint        timeout_); + +/* Create an IO channel for Windows messages for window handle hwnd. */ +#if GLIB_SIZEOF_VOID_P == 8 +/* We use gsize here so that it is still an integer type and not a + * pointer, like the guint in the traditional prototype. We can't use + * intptr_t as that is not portable enough. + */ +GIOChannel *g_io_channel_win32_new_messages (gsize hwnd); +#else +GIOChannel *g_io_channel_win32_new_messages (guint hwnd); +#endif + +/* Create an IO channel for C runtime (emulated Unix-like) file + * descriptors. After calling g_io_add_watch() on a IO channel + * returned by this function, you shouldn't call read() on the file + * descriptor. This is because adding polling for a file descriptor is + * implemented on Win32 by starting a thread that sits blocked in a + * read() from the file descriptor most of the time. All reads from + * the file descriptor should be done by this internal GLib + * thread. Your code should call only g_io_channel_read_chars(). + */ +GIOChannel* g_io_channel_win32_new_fd (gint         fd); + +/* Get the C runtime file descriptor of a channel. */ +gint        g_io_channel_win32_get_fd (GIOChannel *channel); + +/* Create an IO channel for a winsock socket. The parameter should be + * a SOCKET. Contrary to IO channels for file descriptors (on *Win32), + * you can use normal recv() or recvfrom() on sockets even if GLib + * is polling them. + */ +GIOChannel *g_io_channel_win32_new_socket (gint socket); + +#endif + +G_END_DECLS + +#endif /* __G_IOCHANNEL_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gkeyfile.h b/protocols/Sametime/src/glib/include/glib/gkeyfile.h new file mode 100644 index 0000000000..e16dc61272 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gkeyfile.h @@ -0,0 +1,266 @@ +/* gkeyfile.h - desktop entry file parser + * + *  Copyright 2004 Red Hat, Inc. + * + *  Ray Strode <halfline@hawaii.rr.com> + * + * GLib is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * GLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with GLib; see the file COPYING.LIB.  If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + *   Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_KEY_FILE_H__ +#define __G_KEY_FILE_H__ + +#include <glib/gerror.h> + +G_BEGIN_DECLS + +typedef enum +{ +  G_KEY_FILE_ERROR_UNKNOWN_ENCODING, +  G_KEY_FILE_ERROR_PARSE, +  G_KEY_FILE_ERROR_NOT_FOUND, +  G_KEY_FILE_ERROR_KEY_NOT_FOUND, +  G_KEY_FILE_ERROR_GROUP_NOT_FOUND, +  G_KEY_FILE_ERROR_INVALID_VALUE +} GKeyFileError; + +#define G_KEY_FILE_ERROR g_key_file_error_quark() + +GQuark g_key_file_error_quark (void); + +typedef struct _GKeyFile GKeyFile; + +typedef enum +{ +  G_KEY_FILE_NONE              = 0, +  G_KEY_FILE_KEEP_COMMENTS     = 1 << 0, +  G_KEY_FILE_KEEP_TRANSLATIONS = 1 << 1 +} GKeyFileFlags; + +GKeyFile *g_key_file_new                    (void); +void      g_key_file_free                   (GKeyFile             *key_file); +void      g_key_file_set_list_separator     (GKeyFile             *key_file, +					     gchar                 separator); +gboolean  g_key_file_load_from_file         (GKeyFile             *key_file, +					     const gchar          *file, +					     GKeyFileFlags         flags, +					     GError              **error); +gboolean  g_key_file_load_from_data         (GKeyFile             *key_file, +					     const gchar          *data, +					     gsize                 length, +					     GKeyFileFlags         flags, +					     GError              **error); +gboolean g_key_file_load_from_dirs          (GKeyFile             *key_file, +					     const gchar	  *file, +					     const gchar	 **search_dirs, +					     gchar		 **full_path, +					     GKeyFileFlags         flags, +					     GError              **error); +gboolean g_key_file_load_from_data_dirs     (GKeyFile             *key_file, +					     const gchar          *file, +					     gchar               **full_path, +					     GKeyFileFlags         flags, +					     GError              **error); +gchar    *g_key_file_to_data                (GKeyFile             *key_file, +					     gsize                *length, +					     GError              **error) G_GNUC_MALLOC; +gchar    *g_key_file_get_start_group        (GKeyFile             *key_file) G_GNUC_MALLOC; +gchar   **g_key_file_get_groups             (GKeyFile             *key_file, +					     gsize                *length) G_GNUC_MALLOC; +gchar   **g_key_file_get_keys               (GKeyFile             *key_file, +					     const gchar          *group_name, +					     gsize                *length, +					     GError              **error) G_GNUC_MALLOC; +gboolean  g_key_file_has_group              (GKeyFile             *key_file, +					     const gchar          *group_name); +gboolean  g_key_file_has_key                (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     GError              **error); +gchar    *g_key_file_get_value              (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     GError              **error) G_GNUC_MALLOC; +void      g_key_file_set_value              (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     const gchar          *value); +gchar    *g_key_file_get_string             (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     GError              **error) G_GNUC_MALLOC; +void      g_key_file_set_string             (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     const gchar          *string); +gchar    *g_key_file_get_locale_string      (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     const gchar          *locale, +					     GError              **error) G_GNUC_MALLOC; +void      g_key_file_set_locale_string      (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     const gchar          *locale, +					     const gchar          *string); +gboolean  g_key_file_get_boolean            (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     GError              **error); +void      g_key_file_set_boolean            (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     gboolean              value); +gint      g_key_file_get_integer            (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     GError              **error); +void      g_key_file_set_integer            (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     gint                  value); +gint64    g_key_file_get_int64              (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     GError              **error); +void      g_key_file_set_int64              (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     gint64                value); +guint64   g_key_file_get_uint64             (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     GError              **error); +void      g_key_file_set_uint64             (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     guint64               value); +gdouble   g_key_file_get_double             (GKeyFile             *key_file, +                                             const gchar          *group_name, +                                             const gchar          *key, +                                             GError              **error); +void      g_key_file_set_double             (GKeyFile             *key_file, +                                             const gchar          *group_name, +                                             const gchar          *key, +                                             gdouble               value); +gchar   **g_key_file_get_string_list        (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     gsize                *length, +					     GError              **error) G_GNUC_MALLOC; +void      g_key_file_set_string_list        (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     const gchar * const   list[], +					     gsize                 length); +gchar   **g_key_file_get_locale_string_list (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     const gchar          *locale, +					     gsize                *length, +					     GError              **error) G_GNUC_MALLOC; +void      g_key_file_set_locale_string_list (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     const gchar          *locale, +					     const gchar * const   list[], +					     gsize                 length); +gboolean *g_key_file_get_boolean_list       (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     gsize                *length, +					     GError              **error) G_GNUC_MALLOC; +void      g_key_file_set_boolean_list       (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     gboolean              list[], +					     gsize                 length); +gint     *g_key_file_get_integer_list       (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     gsize                *length, +					     GError              **error) G_GNUC_MALLOC; +void      g_key_file_set_double_list        (GKeyFile             *key_file, +                                             const gchar          *group_name, +                                             const gchar          *key, +                                             gdouble               list[], +                                             gsize                 length); +gdouble  *g_key_file_get_double_list        (GKeyFile             *key_file, +                                             const gchar          *group_name, +                                             const gchar          *key, +                                             gsize                *length, +                                             GError              **error) G_GNUC_MALLOC; +void      g_key_file_set_integer_list       (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     gint                  list[], +					     gsize                 length); +gboolean  g_key_file_set_comment            (GKeyFile             *key_file, +                                             const gchar          *group_name, +                                             const gchar          *key, +                                             const gchar          *comment, +                                             GError              **error); +gchar    *g_key_file_get_comment            (GKeyFile             *key_file, +                                             const gchar          *group_name, +                                             const gchar          *key, +                                             GError              **error) G_GNUC_MALLOC; + +gboolean  g_key_file_remove_comment         (GKeyFile             *key_file, +                                             const gchar          *group_name, +                                             const gchar          *key, +					     GError              **error); +gboolean  g_key_file_remove_key             (GKeyFile             *key_file, +					     const gchar          *group_name, +					     const gchar          *key, +					     GError              **error); +gboolean  g_key_file_remove_group           (GKeyFile             *key_file, +					     const gchar          *group_name, +					     GError              **error); + +/* Defines for handling freedesktop.org Desktop files */ +#define G_KEY_FILE_DESKTOP_GROUP                "Desktop Entry" + +#define G_KEY_FILE_DESKTOP_KEY_TYPE             "Type" +#define G_KEY_FILE_DESKTOP_KEY_VERSION          "Version" +#define G_KEY_FILE_DESKTOP_KEY_NAME             "Name" +#define G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME     "GenericName" +#define G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY       "NoDisplay" +#define G_KEY_FILE_DESKTOP_KEY_COMMENT          "Comment" +#define G_KEY_FILE_DESKTOP_KEY_ICON             "Icon" +#define G_KEY_FILE_DESKTOP_KEY_HIDDEN           "Hidden" +#define G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN     "OnlyShowIn" +#define G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN      "NotShowIn" +#define G_KEY_FILE_DESKTOP_KEY_TRY_EXEC         "TryExec" +#define G_KEY_FILE_DESKTOP_KEY_EXEC             "Exec" +#define G_KEY_FILE_DESKTOP_KEY_PATH             "Path" +#define G_KEY_FILE_DESKTOP_KEY_TERMINAL         "Terminal" +#define G_KEY_FILE_DESKTOP_KEY_MIME_TYPE        "MimeType" +#define G_KEY_FILE_DESKTOP_KEY_CATEGORIES       "Categories" +#define G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY   "StartupNotify" +#define G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS "StartupWMClass" +#define G_KEY_FILE_DESKTOP_KEY_URL              "URL" + +#define G_KEY_FILE_DESKTOP_TYPE_APPLICATION     "Application" +#define G_KEY_FILE_DESKTOP_TYPE_LINK            "Link" +#define G_KEY_FILE_DESKTOP_TYPE_DIRECTORY       "Directory" + +G_END_DECLS + +#endif /* __G_KEY_FILE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/glist.h b/protocols/Sametime/src/glib/include/glib/glist.h new file mode 100644 index 0000000000..e74ed96f15 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/glist.h @@ -0,0 +1,120 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_LIST_H__ +#define __G_LIST_H__ + +#include <glib/gmem.h> + +G_BEGIN_DECLS + +typedef struct _GList GList; + +struct _GList +{ +  gpointer data; +  GList *next; +  GList *prev; +}; + +/* Doubly linked lists + */ +GList*   g_list_alloc                   (void) G_GNUC_WARN_UNUSED_RESULT; +void     g_list_free                    (GList            *list); +void     g_list_free_1                  (GList            *list); +#define  g_list_free1                   g_list_free_1 +GList*   g_list_append                  (GList            *list, +					 gpointer          data) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_prepend                 (GList            *list, +					 gpointer          data) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_insert                  (GList            *list, +					 gpointer          data, +					 gint              position) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_insert_sorted           (GList            *list, +					 gpointer          data, +					 GCompareFunc      func) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_insert_sorted_with_data (GList            *list, +					 gpointer          data, +					 GCompareDataFunc  func, +					 gpointer          user_data) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_insert_before           (GList            *list, +					 GList            *sibling, +					 gpointer          data) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_concat                  (GList            *list1, +					 GList            *list2) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_remove                  (GList            *list, +					 gconstpointer     data) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_remove_all              (GList            *list, +					 gconstpointer     data) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_remove_link             (GList            *list, +					 GList            *llink) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_delete_link             (GList            *list, +					 GList            *link_) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_reverse                 (GList            *list) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_copy                    (GList            *list) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_nth                     (GList            *list, +					 guint             n); +GList*   g_list_nth_prev                (GList            *list, +					 guint             n); +GList*   g_list_find                    (GList            *list, +					 gconstpointer     data); +GList*   g_list_find_custom             (GList            *list, +					 gconstpointer     data, +					 GCompareFunc      func); +gint     g_list_position                (GList            *list, +					 GList            *llink); +gint     g_list_index                   (GList            *list, +					 gconstpointer     data); +GList*   g_list_last                    (GList            *list); +GList*   g_list_first                   (GList            *list); +guint    g_list_length                  (GList            *list); +void     g_list_foreach                 (GList            *list, +					 GFunc             func, +					 gpointer          user_data); +GList*   g_list_sort                    (GList            *list, +					 GCompareFunc      compare_func) G_GNUC_WARN_UNUSED_RESULT; +GList*   g_list_sort_with_data          (GList            *list, +					 GCompareDataFunc  compare_func, +					 gpointer          user_data)  G_GNUC_WARN_UNUSED_RESULT; +gpointer g_list_nth_data                (GList            *list, +					 guint             n); + + +#define g_list_previous(list)	        ((list) ? (((GList *)(list))->prev) : NULL) +#define g_list_next(list)	        ((list) ? (((GList *)(list))->next) : NULL) + +#ifndef G_DISABLE_DEPRECATED +void     g_list_push_allocator          (gpointer          allocator); +void     g_list_pop_allocator           (void); +#endif + +G_END_DECLS + +#endif /* __G_LIST_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gmacros.h b/protocols/Sametime/src/glib/include/glib/gmacros.h new file mode 100644 index 0000000000..9f9c25dcb1 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gmacros.h @@ -0,0 +1,284 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +/* This file must not include any other glib header file and must thus + * not refer to variables from glibconfig.h + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_MACROS_H__ +#define __G_MACROS_H__ + +/* We include stddef.h to get the system's definition of NULL + */ +#include <stddef.h> + +/* Here we provide G_GNUC_EXTENSION as an alias for __extension__, + * where this is valid. This allows for warningless compilation of + * "long long" types even in the presence of '-ansi -pedantic'.  + */ +#if     __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) +#  define G_GNUC_EXTENSION __extension__ +#else +#  define G_GNUC_EXTENSION +#endif + +/* Provide macros to feature the GCC function attribute. + */ +#if    __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) +#define G_GNUC_PURE                            \ +  __attribute__((__pure__)) +#define G_GNUC_MALLOC    			\ +  __attribute__((__malloc__)) +#else +#define G_GNUC_PURE +#define G_GNUC_MALLOC +#endif + +#if     __GNUC__ >= 4 +#define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__)) +#else +#define G_GNUC_NULL_TERMINATED +#endif + +#if     (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) +#define G_GNUC_ALLOC_SIZE(x) __attribute__((__alloc_size__(x))) +#define G_GNUC_ALLOC_SIZE2(x,y) __attribute__((__alloc_size__(x,y))) +#else +#define G_GNUC_ALLOC_SIZE(x) +#define G_GNUC_ALLOC_SIZE2(x,y) +#endif + +#if     __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +#define G_GNUC_PRINTF( format_idx, arg_idx )    \ +  __attribute__((__format__ (__printf__, format_idx, arg_idx))) +#define G_GNUC_SCANF( format_idx, arg_idx )     \ +  __attribute__((__format__ (__scanf__, format_idx, arg_idx))) +#define G_GNUC_FORMAT( arg_idx )                \ +  __attribute__((__format_arg__ (arg_idx))) +#define G_GNUC_NORETURN                         \ +  __attribute__((__noreturn__)) +#define G_GNUC_CONST                            \ +  __attribute__((__const__)) +#define G_GNUC_UNUSED                           \ +  __attribute__((__unused__)) +#define G_GNUC_NO_INSTRUMENT			\ +  __attribute__((__no_instrument_function__)) +#else   /* !__GNUC__ */ +#define G_GNUC_PRINTF( format_idx, arg_idx ) +#define G_GNUC_SCANF( format_idx, arg_idx ) +#define G_GNUC_FORMAT( arg_idx ) +#define G_GNUC_NORETURN +#define G_GNUC_CONST +#define G_GNUC_UNUSED +#define G_GNUC_NO_INSTRUMENT +#endif  /* !__GNUC__ */ + +#if    __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +#define G_GNUC_DEPRECATED                            \ +  __attribute__((__deprecated__)) +#else +#define G_GNUC_DEPRECATED +#endif /* __GNUC__ */ + +#if    __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +#define G_GNUC_DEPRECATED_FOR(f)                        \ +  __attribute__((deprecated("Use " #f " instead"))) +#else +#define G_GNUC_DEPRECATED_FOR(f)        G_GNUC_DEPRECATED +#endif /* __GNUC__ */ + +#if     __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +#  define G_GNUC_MAY_ALIAS __attribute__((may_alias)) +#else +#  define G_GNUC_MAY_ALIAS +#endif + +#if    __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define G_GNUC_WARN_UNUSED_RESULT 		\ +  __attribute__((warn_unused_result)) +#else +#define G_GNUC_WARN_UNUSED_RESULT +#endif /* __GNUC__ */ + +#ifndef G_DISABLE_DEPRECATED +/* Wrap the gcc __PRETTY_FUNCTION__ and __FUNCTION__ variables with + * macros, so we can refer to them as strings unconditionally. + * usage not-recommended since gcc-3.0 + */ +#if defined (__GNUC__) && (__GNUC__ < 3) +#define G_GNUC_FUNCTION         __FUNCTION__ +#define G_GNUC_PRETTY_FUNCTION  __PRETTY_FUNCTION__ +#else   /* !__GNUC__ */ +#define G_GNUC_FUNCTION         "" +#define G_GNUC_PRETTY_FUNCTION  "" +#endif  /* !__GNUC__ */ +#endif  /* !G_DISABLE_DEPRECATED */ + +#define G_STRINGIFY(macro_or_string)	G_STRINGIFY_ARG (macro_or_string) +#define	G_STRINGIFY_ARG(contents)	#contents + +#define G_PASTE_ARGS(identifier1,identifier2) identifier1 ## identifier2 +#define G_PASTE(identifier1,identifier2)      G_PASTE_ARGS (identifier1, identifier2) +#define G_STATIC_ASSERT(expr) typedef struct { char Compile_Time_Assertion[(expr) ? 1 : -1]; } G_PASTE (_GStaticAssert_, __LINE__) + +/* Provide a string identifying the current code position */ +#if defined(__GNUC__) && (__GNUC__ < 3) && !defined(__cplusplus) +#  define G_STRLOC	__FILE__ ":" G_STRINGIFY (__LINE__) ":" __PRETTY_FUNCTION__ "()" +#else +#  define G_STRLOC	__FILE__ ":" G_STRINGIFY (__LINE__) +#endif + +/* Provide a string identifying the current function, non-concatenatable */ +#if defined (__GNUC__) +#  define G_STRFUNC     ((const char*) (__PRETTY_FUNCTION__)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 19901L +#  define G_STRFUNC     ((const char*) (__func__)) +#else +#  define G_STRFUNC     ((const char*) ("???")) +#endif + +/* Guard C code in headers, while including them from C++ */ +#ifdef  __cplusplus +# define G_BEGIN_DECLS  extern "C" { +# define G_END_DECLS    } +#else +# define G_BEGIN_DECLS +# define G_END_DECLS +#endif + +/* Provide definitions for some commonly used macros. + *  Some of them are only provided if they haven't already + *  been defined. It is assumed that if they are already + *  defined then the current definition is correct. + */ +#ifndef NULL +#  ifdef __cplusplus +#    define NULL        (0L) +#  else /* !__cplusplus */ +#    define NULL        ((void*) 0) +#  endif /* !__cplusplus */ +#endif + +#ifndef	FALSE +#define	FALSE	(0) +#endif + +#ifndef	TRUE +#define	TRUE	(!FALSE) +#endif + +#undef	MAX +#define MAX(a, b)  (((a) > (b)) ? (a) : (b)) + +#undef	MIN +#define MIN(a, b)  (((a) < (b)) ? (a) : (b)) + +#undef	ABS +#define ABS(a)	   (((a) < 0) ? -(a) : (a)) + +#undef	CLAMP +#define CLAMP(x, low, high)  (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) + +/* Count the number of elements in an array. The array must be defined + * as such; using this with a dynamically allocated array will give + * incorrect results. + */ +#define G_N_ELEMENTS(arr)		(sizeof (arr) / sizeof ((arr)[0])) + +/* Macros by analogy to GINT_TO_POINTER, GPOINTER_TO_INT + */ +#define GPOINTER_TO_SIZE(p)	((gsize) (p)) +#define GSIZE_TO_POINTER(s)	((gpointer) (gsize) (s)) + +/* Provide convenience macros for handling structure + * fields through their offsets. + */ + +#if defined(__GNUC__)  && __GNUC__ >= 4 +#  define G_STRUCT_OFFSET(struct_type, member) \ +      ((glong) offsetof (struct_type, member)) +#else +#  define G_STRUCT_OFFSET(struct_type, member)	\ +      ((glong) ((guint8*) &((struct_type*) 0)->member)) +#endif + +#define G_STRUCT_MEMBER_P(struct_p, struct_offset)   \ +    ((gpointer) ((guint8*) (struct_p) + (glong) (struct_offset))) +#define G_STRUCT_MEMBER(member_type, struct_p, struct_offset)   \ +    (*(member_type*) G_STRUCT_MEMBER_P ((struct_p), (struct_offset))) + +/* Provide simple macro statement wrappers: + *   G_STMT_START { statements; } G_STMT_END; + * This can be used as a single statement, like: + *   if (x) G_STMT_START { ... } G_STMT_END; else ... + * This intentionally does not use compiler extensions like GCC's '({...})' to + * avoid portability issue or side effects when compiled with different compilers. + */ +#if !(defined (G_STMT_START) && defined (G_STMT_END)) +#  define G_STMT_START  do +#  define G_STMT_END    while (0) +#endif + +/* Allow the app programmer to select whether or not return values + * (usually char*) are const or not.  Don't try using this feature for + * functions with C++ linkage. + */ +#ifdef G_DISABLE_CONST_RETURNS +#define G_CONST_RETURN +#else +#define G_CONST_RETURN const +#endif + +/* + * The G_LIKELY and G_UNLIKELY macros let the programmer give hints to  + * the compiler about the expected result of an expression. Some compilers + * can use this information for optimizations. + * + * The _G_BOOLEAN_EXPR macro is intended to trigger a gcc warning when + * putting assignments in g_return_if_fail ().   + */ +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +#define _G_BOOLEAN_EXPR(expr)                   \ + __extension__ ({                               \ +   int _g_boolean_var_;                         \ +   if (expr)                                    \ +      _g_boolean_var_ = 1;                      \ +   else                                         \ +      _g_boolean_var_ = 0;                      \ +   _g_boolean_var_;                             \ +}) +#define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1)) +#define G_UNLIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 0)) +#else +#define G_LIKELY(expr) (expr) +#define G_UNLIKELY(expr) (expr) +#endif + +#endif /* __G_MACROS_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gmain.h b/protocols/Sametime/src/glib/include/glib/gmain.h new file mode 100644 index 0000000000..24c6171fe6 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gmain.h @@ -0,0 +1,531 @@ +/* gmain.h - the GLib Main loop + * Copyright (C) 1998-2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_MAIN_H__ +#define __G_MAIN_H__ + +#include <glib/gpoll.h> +#include <glib/gslist.h> +#include <glib/gthread.h> + +G_BEGIN_DECLS + +/** + * GMainContext: + * + * The <structname>GMainContext</structname> struct is an opaque data + * type representing a set of sources to be handled in a main loop. + */ +typedef struct _GMainContext            GMainContext; + +/** + * GMainLoop: + * + * The <structname>GMainLoop</structname> struct is an opaque data type + * representing the main event loop of a GLib or GTK+ application. + */ +typedef struct _GMainLoop               GMainLoop; + +/** + * GSource: + * + * The <structname>GSource</structname> struct is an opaque data type + * representing an event source. + */ +typedef struct _GSource                 GSource; + +/** + * GSourceCallbackFuncs: + * @ref: Called when a reference is added to the callback object + * @unref: Called when a reference to the callback object is dropped + * @get: Called to extract the callback function and data from the + *     callback object. + + * The <structname>GSourceCallbackFuncs</structname> struct contains + * functions for managing callback objects. + */ +typedef struct _GSourceCallbackFuncs    GSourceCallbackFuncs; + +/** + * GSourceFuncs: + * @prepare: Called before all the file descriptors are polled. If the + *     source can determine that it is ready here (without waiting for the + *     results of the poll() call) it should return %TRUE. It can also return + *     a @timeout_ value which should be the maximum timeout (in milliseconds) + *     which should be passed to the poll() call. The actual timeout used will + *     be -1 if all sources returned -1, or it will be the minimum of all the + *     @timeout_ values returned which were >= 0. + * @check: Called after all the file descriptors are polled. The source + *     should return %TRUE if it is ready to be dispatched. Note that some + *     time may have passed since the previous prepare function was called, + *     so the source should be checked again here. + * @dispatch: Called to dispatch the event source, after it has returned + *     %TRUE in either its @prepare or its @check function. The @dispatch + *     function is passed in a callback function and data. The callback + *     function may be %NULL if the source was never connected to a callback + *     using g_source_set_callback(). The @dispatch function should call the + *     callback function with @user_data and whatever additional parameters + *     are needed for this type of event source. + * @finalize: Called when the source is finalized. + * @closure_callback: + * @closure_marshal: + * + * The <structname>GSourceFuncs</structname> struct contains a table of + * functions used to handle event sources in a generic manner. + * + * For idle sources, the prepare and check functions always return %TRUE + * to indicate that the source is always ready to be processed. The prepare + * function also returns a timeout value of 0 to ensure that the poll() call + * doesn't block (since that would be time wasted which could have been spent + * running the idle function). + * + * For timeout sources, the prepare and check functions both return %TRUE + * if the timeout interval has expired. The prepare function also returns + * a timeout value to ensure that the poll() call doesn't block too long + * and miss the next timeout. + * + * For file descriptor sources, the prepare function typically returns %FALSE, + * since it must wait until poll() has been called before it knows whether + * any events need to be processed. It sets the returned timeout to -1 to + * indicate that it doesn't mind how long the poll() call blocks. In the + * check function, it tests the results of the poll() call to see if the + * required condition has been met, and returns %TRUE if so. + */ +typedef struct _GSourceFuncs            GSourceFuncs; + +/** + * GPid: + * + * A type which is used to hold a process identification. + * + * On UNIX, processes are identified by a process id (an integer), + * while Windows uses process handles (which are pointers). + */ + +typedef gboolean (*GSourceFunc)       (gpointer data); + +/** + * GChildWatchFunc: + * @pid: the process id of the child process + * @status: Status information about the child process, + *     see waitpid(2) for more information about this field + * @data: user data passed to g_child_watch_add() + * + * The type of functions to be called when a child exists. + */ +typedef void     (*GChildWatchFunc)   (GPid     pid, +                                       gint     status, +                                       gpointer data); +struct _GSource +{ +  /*< private >*/ +  gpointer callback_data; +  GSourceCallbackFuncs *callback_funcs; + +  GSourceFuncs *source_funcs; +  guint ref_count; + +  GMainContext *context; + +  gint priority; +  guint flags; +  guint source_id; + +  GSList *poll_fds; +   +  GSource *prev; +  GSource *next; + +  char    *name; +  gpointer reserved2; +}; + +struct _GSourceCallbackFuncs +{ +  void (*ref)   (gpointer     cb_data); +  void (*unref) (gpointer     cb_data); +  void (*get)   (gpointer     cb_data, +                 GSource     *source,  +                 GSourceFunc *func, +                 gpointer    *data); +}; + +typedef void (*GSourceDummyMarshal) (void); + +struct _GSourceFuncs +{ +  gboolean (*prepare)  (GSource    *source, +                        gint       *timeout_); +  gboolean (*check)    (GSource    *source); +  gboolean (*dispatch) (GSource    *source, +                        GSourceFunc callback, +                        gpointer    user_data); +  void     (*finalize) (GSource    *source); /* Can be NULL */ + +  /* For use by g_source_set_closure */ +  GSourceFunc     closure_callback;         +  GSourceDummyMarshal closure_marshal; /* Really is of type GClosureMarshal */ +}; + +/* Standard priorities */ + +/** + * G_PRIORITY_HIGH: + * + * Use this for high priority event sources. + * + * It is not used within GLib or GTK+. + */ +#define G_PRIORITY_HIGH            -100 + +/** + * G_PRIORITY_DEFAULT: + * + * Use this for default priority event sources. + * + * In GLib this priority is used when adding timeout functions + * with g_timeout_add(). In GDK this priority is used for events + * from the X server. + */ +#define G_PRIORITY_DEFAULT          0 + +/** + * G_PRIORITY_HIGH_IDLE: + * + * Use this for high priority idle functions. + * + * GTK+ uses #G_PRIORITY_HIGH_IDLE + 10 for resizing operations, + * and #G_PRIORITY_HIGH_IDLE + 20 for redrawing operations. (This is + * done to ensure that any pending resizes are processed before any + * pending redraws, so that widgets are not redrawn twice unnecessarily.) + */ +#define G_PRIORITY_HIGH_IDLE        100 + +/** + * G_PRIORITY_DEFAULT_IDLE: + * + * Use this for default priority idle functions. + * + * In GLib this priority is used when adding idle functions with + * g_idle_add(). + */ +#define G_PRIORITY_DEFAULT_IDLE     200 + +/** + * G_PRIORITY_LOW: + * + * Use this for very low priority background tasks. + * + * It is not used within GLib or GTK+. + */ +#define G_PRIORITY_LOW              300 + +/* GMainContext: */ + +GMainContext *g_main_context_new       (void); +GMainContext *g_main_context_ref       (GMainContext *context); +void          g_main_context_unref     (GMainContext *context); +GMainContext *g_main_context_default   (void); + +gboolean      g_main_context_iteration (GMainContext *context, +                                        gboolean      may_block); +gboolean      g_main_context_pending   (GMainContext *context); + +/* For implementation of legacy interfaces + */ +GSource      *g_main_context_find_source_by_id              (GMainContext *context, +                                                             guint         source_id); +GSource      *g_main_context_find_source_by_user_data       (GMainContext *context, +                                                             gpointer      user_data); +GSource      *g_main_context_find_source_by_funcs_user_data (GMainContext *context, +                                                             GSourceFuncs *funcs, +                                                             gpointer      user_data); + +/* Low level functions for implementing custom main loops. + */ +void     g_main_context_wakeup  (GMainContext *context); +gboolean g_main_context_acquire (GMainContext *context); +void     g_main_context_release (GMainContext *context); +gboolean g_main_context_is_owner (GMainContext *context); +gboolean g_main_context_wait    (GMainContext *context, +                                 GCond        *cond, +                                 GMutex       *mutex); + +gboolean g_main_context_prepare  (GMainContext *context, +                                  gint         *priority); +gint     g_main_context_query    (GMainContext *context, +                                  gint          max_priority, +                                  gint         *timeout_, +                                  GPollFD      *fds, +                                  gint          n_fds); +gint     g_main_context_check    (GMainContext *context, +                                  gint          max_priority, +                                  GPollFD      *fds, +                                  gint          n_fds); +void     g_main_context_dispatch (GMainContext *context); + +void     g_main_context_set_poll_func (GMainContext *context, +                                       GPollFunc     func); +GPollFunc g_main_context_get_poll_func (GMainContext *context); + +/* Low level functions for use by source implementations + */ +void     g_main_context_add_poll    (GMainContext *context, +                                     GPollFD      *fd, +                                     gint          priority); +void     g_main_context_remove_poll (GMainContext *context, +                                     GPollFD      *fd); + +gint     g_main_depth               (void); +GSource *g_main_current_source      (void); + +/* GMainContexts for other threads + */ +void          g_main_context_push_thread_default (GMainContext *context); +void          g_main_context_pop_thread_default  (GMainContext *context); +GMainContext *g_main_context_get_thread_default  (void); + +/* GMainLoop: */ + +GMainLoop *g_main_loop_new        (GMainContext *context, +                                   gboolean      is_running); +void       g_main_loop_run        (GMainLoop    *loop); +void       g_main_loop_quit       (GMainLoop    *loop); +GMainLoop *g_main_loop_ref        (GMainLoop    *loop); +void       g_main_loop_unref      (GMainLoop    *loop); +gboolean   g_main_loop_is_running (GMainLoop    *loop); +GMainContext *g_main_loop_get_context (GMainLoop    *loop); + +/* GSource: */ + +GSource *g_source_new             (GSourceFuncs   *source_funcs, +                                   guint           struct_size); +GSource *g_source_ref             (GSource        *source); +void     g_source_unref           (GSource        *source); + +guint    g_source_attach          (GSource        *source, +                                   GMainContext   *context); +void     g_source_destroy         (GSource        *source); + +void     g_source_set_priority    (GSource        *source, +                                   gint            priority); +gint     g_source_get_priority    (GSource        *source); +void     g_source_set_can_recurse (GSource        *source, +                                   gboolean        can_recurse); +gboolean g_source_get_can_recurse (GSource        *source); +guint    g_source_get_id          (GSource        *source); + +GMainContext *g_source_get_context (GSource       *source); + +void     g_source_set_callback    (GSource        *source, +                                   GSourceFunc     func, +                                   gpointer        data, +                                   GDestroyNotify  notify); + +void     g_source_set_funcs       (GSource        *source, +                                   GSourceFuncs   *funcs); +gboolean g_source_is_destroyed    (GSource        *source); + +void                 g_source_set_name       (GSource        *source, +                                              const char     *name); +G_CONST_RETURN char* g_source_get_name       (GSource        *source); +void                 g_source_set_name_by_id (guint           tag, +                                              const char     *name); + + +/* Used to implement g_source_connect_closure and internally*/ +void g_source_set_callback_indirect (GSource              *source, +                                     gpointer              callback_data, +                                     GSourceCallbackFuncs *callback_funcs); + +void     g_source_add_poll         (GSource        *source, +                                    GPollFD        *fd); +void     g_source_remove_poll      (GSource        *source, +                                    GPollFD        *fd); + +void     g_source_get_current_time (GSource        *source, +                                    GTimeVal       *timeval); + + /* void g_source_connect_closure (GSource        *source, +                                  GClosure       *closure); + */ + +/* Specific source types + */ +GSource *g_idle_source_new        (void); +GSource *g_child_watch_source_new (GPid pid); +GSource *g_timeout_source_new     (guint interval); +GSource *g_timeout_source_new_seconds (guint interval); + +/* Miscellaneous functions + */ +void g_get_current_time                 (GTimeVal       *result); + +/* ============== Compat main loop stuff ================== */ + +#ifndef G_DISABLE_DEPRECATED + +/** + * g_main_new: + * @is_running: set to %TRUE to indicate that the loop is running. This + *     is not very important since calling g_main_run() will set this + *     to %TRUE anyway. + * + * Creates a new #GMainLoop for th default main context. + * + * Returns: a new #GMainLoop + * + * Deprecated: 2.2: Use g_main_loop_new() instead + */ +#define         g_main_new(is_running)  g_main_loop_new (NULL, is_running) + +/** + * g_main_run: + * @loop: a #GMainLoop + * + * Runs a main loop until it stops running. + * + * Deprecated: 2.2: Use g_main_loop_run() instead + */ +#define         g_main_run(loop)        g_main_loop_run(loop) + +/** + * g_main_quit: + * @loop: a #GMainLoop + * + * Stops the #GMainLoop. + * If g_main_run() was called to run the #GMainLoop, it will now return. + * + * Deprecated: 2.2: Use g_main_loop_quit() instead + */ +#define g_main_quit(loop)       g_main_loop_quit(loop) + +/** + * g_main_destroy: + * @loop: a #GMainLoop + * + * Frees the memory allocated for the #GMainLoop. + * + * Deprecated: 2.2: Use g_main_loop_unref() instead + */ +#define g_main_destroy(loop)    g_main_loop_unref(loop) + +/** + * g_main_is_running: + * @loop: a #GMainLoop + * + * Checks if the main loop is running. + * + * Returns: %TRUE if the main loop is running + * + * Deprecated: 2.2: Use g_main_loop_is_running() instead + */ +#define g_main_is_running(loop) g_main_loop_is_running(loop) + +/** + * g_main_iteration: + * @may_block: set to %TRUE if it should block (i.e. wait) until an event + *     source becomes ready. It will return after an event source has been + *     processed. If set to %FALSE it will return immediately if no event + *     source is ready to be processed. + * + * Runs a single iteration for the default #GMainContext. + * + * Returns: %TRUE if more events are pending. + * + * Deprecated: 2.2: Use g_main_context_iteration() instead. + */ +#define g_main_iteration(may_block) g_main_context_iteration (NULL, may_block) + +/** + * g_main_pending: + * + * Checks if any events are pending for the default #GMainContext + * (i.e. ready to be processed). + * + * Returns: %TRUE if any events are pending. + * + * Deprected: 2.2: Use g_main_context_pending() instead. + */ +#define g_main_pending()            g_main_context_pending (NULL) + +/** + * g_main_set_poll_func: + * @func: the function to call to poll all file descriptors + * + * Sets the function to use for the handle polling of file descriptors + * for the default main context. + * + * Deprecated: 2.2: Use g_main_context_set_poll_func() again + */ +#define g_main_set_poll_func(func)  g_main_context_set_poll_func (NULL, func) + +#endif /* G_DISABLE_DEPRECATED */ + +/* Source manipulation by ID */ +gboolean g_source_remove                     (guint          tag); +gboolean g_source_remove_by_user_data        (gpointer       user_data); +gboolean g_source_remove_by_funcs_user_data  (GSourceFuncs  *funcs, +                                              gpointer       user_data); + +/* Idles, child watchers and timeouts */ +guint    g_timeout_add_full         (gint            priority, +                                     guint           interval, +                                     GSourceFunc     function, +                                     gpointer        data, +                                     GDestroyNotify  notify); +guint    g_timeout_add              (guint           interval, +                                     GSourceFunc     function, +                                     gpointer        data); +guint    g_timeout_add_seconds_full (gint            priority, +                                     guint           interval, +                                     GSourceFunc     function, +                                     gpointer        data, +                                     GDestroyNotify  notify); +guint    g_timeout_add_seconds      (guint           interval, +                                     GSourceFunc     function, +                                     gpointer        data); +guint    g_child_watch_add_full     (gint            priority, +                                     GPid            pid, +                                     GChildWatchFunc function, +                                     gpointer        data, +                                     GDestroyNotify  notify); +guint    g_child_watch_add          (GPid            pid, +                                     GChildWatchFunc function, +                                     gpointer        data); +guint    g_idle_add                 (GSourceFunc     function, +                                     gpointer        data); +guint    g_idle_add_full            (gint            priority, +                                     GSourceFunc     function, +                                     gpointer        data, +                                     GDestroyNotify  notify); +gboolean g_idle_remove_by_data      (gpointer        data); + +/* Hook for GClosure / GSource integration. Don't touch */ +GLIB_VAR GSourceFuncs g_timeout_funcs; +GLIB_VAR GSourceFuncs g_child_watch_funcs; +GLIB_VAR GSourceFuncs g_idle_funcs; + +G_END_DECLS + +#endif /* __G_MAIN_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gmappedfile.h b/protocols/Sametime/src/glib/include/glib/gmappedfile.h new file mode 100644 index 0000000000..dbb3f89e6a --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gmappedfile.h @@ -0,0 +1,49 @@ +/* GLIB - Library of useful routines for C programming + * gmappedfile.h: Simplified wrapper around the mmap function + * + * Copyright 2005 Matthias Clasen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_MAPPED_FILE_H__ +#define __G_MAPPED_FILE_H__ + +#include <glib/gerror.h> + +G_BEGIN_DECLS + +typedef struct _GMappedFile GMappedFile; + +GMappedFile *g_mapped_file_new          (const gchar  *filename, +				         gboolean      writable, +				         GError      **error) G_GNUC_MALLOC; +gsize        g_mapped_file_get_length   (GMappedFile  *file); +gchar       *g_mapped_file_get_contents (GMappedFile  *file); +GMappedFile *g_mapped_file_ref          (GMappedFile  *file); +void         g_mapped_file_unref        (GMappedFile  *file); + +#ifndef G_DISABLE_DEPRECATED +void         g_mapped_file_free         (GMappedFile  *file); +#endif + +G_END_DECLS + +#endif /* __G_MAPPED_FILE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gmarkup.h b/protocols/Sametime/src/glib/include/glib/gmarkup.h new file mode 100644 index 0000000000..7bfc08641c --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gmarkup.h @@ -0,0 +1,163 @@ +/* gmarkup.h - Simple XML-like string parser/writer + * + *  Copyright 2000 Red Hat, Inc. + * + * GLib is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * GLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with GLib; see the file COPYING.LIB.  If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + *   Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_MARKUP_H__ +#define __G_MARKUP_H__ + +#include <stdarg.h> + +#include <glib/gerror.h> +#include <glib/gslist.h> + +G_BEGIN_DECLS + +typedef enum +{ +  G_MARKUP_ERROR_BAD_UTF8, +  G_MARKUP_ERROR_EMPTY, +  G_MARKUP_ERROR_PARSE, +  /* The following are primarily intended for specific GMarkupParser +   * implementations to set. +   */ +  G_MARKUP_ERROR_UNKNOWN_ELEMENT, +  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, +  G_MARKUP_ERROR_INVALID_CONTENT, +  G_MARKUP_ERROR_MISSING_ATTRIBUTE +} GMarkupError; + +#define G_MARKUP_ERROR g_markup_error_quark () + +GQuark g_markup_error_quark (void); + +typedef enum +{ +  G_MARKUP_DO_NOT_USE_THIS_UNSUPPORTED_FLAG = 1 << 0, +  G_MARKUP_TREAT_CDATA_AS_TEXT              = 1 << 1, +  G_MARKUP_PREFIX_ERROR_POSITION            = 1 << 2 +} GMarkupParseFlags; + +typedef struct _GMarkupParseContext GMarkupParseContext; +typedef struct _GMarkupParser GMarkupParser; + +struct _GMarkupParser +{ +  /* Called for open tags <foo bar="baz"> */ +  void (*start_element)  (GMarkupParseContext *context, +                          const gchar         *element_name, +                          const gchar        **attribute_names, +                          const gchar        **attribute_values, +                          gpointer             user_data, +                          GError             **error); + +  /* Called for close tags </foo> */ +  void (*end_element)    (GMarkupParseContext *context, +                          const gchar         *element_name, +                          gpointer             user_data, +                          GError             **error); + +  /* Called for character data */ +  /* text is not nul-terminated */ +  void (*text)           (GMarkupParseContext *context, +                          const gchar         *text, +                          gsize                text_len,   +                          gpointer             user_data, +                          GError             **error); + +  /* Called for strings that should be re-saved verbatim in this same +   * position, but are not otherwise interpretable.  At the moment +   * this includes comments and processing instructions. +   */ +  /* text is not nul-terminated. */ +  void (*passthrough)    (GMarkupParseContext *context, +                          const gchar         *passthrough_text, +                          gsize                text_len,   +                          gpointer             user_data, +                          GError             **error); + +  /* Called on error, including one set by other +   * methods in the vtable. The GError should not be freed. +   */ +  void (*error)          (GMarkupParseContext *context, +                          GError              *error, +                          gpointer             user_data); +}; + +GMarkupParseContext *g_markup_parse_context_new   (const GMarkupParser *parser, +                                                   GMarkupParseFlags    flags, +                                                   gpointer             user_data, +                                                   GDestroyNotify       user_data_dnotify); +void                 g_markup_parse_context_free  (GMarkupParseContext *context); +gboolean             g_markup_parse_context_parse (GMarkupParseContext *context, +                                                   const gchar         *text, +                                                   gssize               text_len,   +                                                   GError             **error); +void                 g_markup_parse_context_push  (GMarkupParseContext *context, +                                                   const GMarkupParser *parser, +                                                   gpointer             user_data); +gpointer             g_markup_parse_context_pop   (GMarkupParseContext *context); +                                                    +gboolean             g_markup_parse_context_end_parse (GMarkupParseContext *context, +                                                       GError             **error); +G_CONST_RETURN gchar *g_markup_parse_context_get_element (GMarkupParseContext *context); +G_CONST_RETURN GSList *g_markup_parse_context_get_element_stack (GMarkupParseContext *context); + +/* For user-constructed error messages, has no precise semantics */ +void                 g_markup_parse_context_get_position (GMarkupParseContext *context, +                                                          gint                *line_number, +                                                          gint                *char_number); +gpointer             g_markup_parse_context_get_user_data (GMarkupParseContext *context); + +/* useful when saving */ +gchar* g_markup_escape_text (const gchar *text, +                             gssize       length);   + +gchar *g_markup_printf_escaped (const char *format, +				...) G_GNUC_PRINTF (1, 2); +gchar *g_markup_vprintf_escaped (const char *format, +				 va_list     args); + +typedef enum +{ +  G_MARKUP_COLLECT_INVALID, +  G_MARKUP_COLLECT_STRING, +  G_MARKUP_COLLECT_STRDUP, +  G_MARKUP_COLLECT_BOOLEAN, +  G_MARKUP_COLLECT_TRISTATE, + +  G_MARKUP_COLLECT_OPTIONAL = (1 << 16) +} GMarkupCollectType; + + +/* useful from start_element */ +gboolean   g_markup_collect_attributes (const gchar         *element_name, +                                        const gchar        **attribute_names, +                                        const gchar        **attribute_values, +                                        GError             **error, +                                        GMarkupCollectType   first_type, +                                        const gchar         *first_attr, +                                        ...); + +G_END_DECLS + +#endif /* __G_MARKUP_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gmem.h b/protocols/Sametime/src/glib/include/glib/gmem.h new file mode 100644 index 0000000000..01d953e6c5 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gmem.h @@ -0,0 +1,309 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_MEM_H__ +#define __G_MEM_H__ + +#include <glib/gslice.h> +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +/** + * GMemVTable: + * @malloc: function to use for allocating memory. + * @realloc: function to use for reallocating memory. + * @free: function to use to free memory. + * @calloc: function to use for allocating zero-filled memory. + * @try_malloc: function to use for allocating memory without a default error handler. + * @try_realloc: function to use for reallocating memory without a default error handler. + *  + * A set of functions used to perform memory allocation. The same #GMemVTable must + * be used for all allocations in the same program; a call to g_mem_set_vtable(), + * if it exists, should be prior to any use of GLib. + */ +typedef struct _GMemVTable GMemVTable; + + +#if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_LONG +/** + * G_MEM_ALIGN: + *  + * Indicates the number of bytes to which memory will be aligned on the + * current platform. + */ +#  define G_MEM_ALIGN	GLIB_SIZEOF_VOID_P +#else	/* GLIB_SIZEOF_VOID_P <= GLIB_SIZEOF_LONG */ +#  define G_MEM_ALIGN	GLIB_SIZEOF_LONG +#endif	/* GLIB_SIZEOF_VOID_P <= GLIB_SIZEOF_LONG */ + + +/* Memory allocation functions + */ + +void	 g_free	          (gpointer	 mem); + +gpointer g_malloc         (gsize	 n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); +gpointer g_malloc0        (gsize	 n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); +gpointer g_realloc        (gpointer	 mem, +			   gsize	 n_bytes) G_GNUC_WARN_UNUSED_RESULT; +gpointer g_try_malloc     (gsize	 n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); +gpointer g_try_malloc0    (gsize	 n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); +gpointer g_try_realloc    (gpointer	 mem, +			   gsize	 n_bytes) G_GNUC_WARN_UNUSED_RESULT; + +gpointer g_malloc_n       (gsize	 n_blocks, +			   gsize	 n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2); +gpointer g_malloc0_n      (gsize	 n_blocks, +			   gsize	 n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2); +gpointer g_realloc_n      (gpointer	 mem, +			   gsize	 n_blocks, +			   gsize	 n_block_bytes) G_GNUC_WARN_UNUSED_RESULT; +gpointer g_try_malloc_n   (gsize	 n_blocks, +			   gsize	 n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2); +gpointer g_try_malloc0_n  (gsize	 n_blocks, +			   gsize	 n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2); +gpointer g_try_realloc_n  (gpointer	 mem, +			   gsize	 n_blocks, +			   gsize	 n_block_bytes) G_GNUC_WARN_UNUSED_RESULT; + + +/* Optimise: avoid the call to the (slower) _n function if we can + * determine at compile-time that no overflow happens. + */ +#if defined (__GNUC__) && (__GNUC__ >= 2) && defined (__OPTIMIZE__) +#  define _G_NEW(struct_type, n_structs, func) \ +	(struct_type *) (__extension__ ({			\ +	  gsize __n = (gsize) (n_structs);			\ +	  gsize __s = sizeof (struct_type);			\ +	  gpointer __p;						\ +	  if (__s == 1)						\ +	    __p = g_##func (__n);				\ +	  else if (__builtin_constant_p (__n) &&		\ +	           (__s == 0 || __n <= G_MAXSIZE / __s))	\ +	    __p = g_##func (__n * __s);				\ +	  else							\ +	    __p = g_##func##_n (__n, __s);			\ +	  __p;							\ +	})) +#  define _G_RENEW(struct_type, mem, n_structs, func) \ +	(struct_type *) (__extension__ ({			\ +	  gsize __n = (gsize) (n_structs);			\ +	  gsize __s = sizeof (struct_type);			\ +	  gpointer __p = (gpointer) (mem);			\ +	  if (__s == 1)						\ +	    __p = g_##func (__p, __n);				\ +	  else if (__builtin_constant_p (__n) &&		\ +	           (__s == 0 || __n <= G_MAXSIZE / __s))	\ +	    __p = g_##func (__p, __n * __s);			\ +	  else							\ +	    __p = g_##func##_n (__p, __n, __s);			\ +	  __p;							\ +	})) + +#else + +/* Unoptimised version: always call the _n() function. */ + +#define _G_NEW(struct_type, n_structs, func) \ +        ((struct_type *) g_##func##_n ((n_structs), sizeof (struct_type))) +#define _G_RENEW(struct_type, mem, n_structs, func) \ +        ((struct_type *) g_##func##_n (mem, (n_structs), sizeof (struct_type))) + +#endif + +/** + * g_new: + * @struct_type: the type of the elements to allocate + * @n_structs: the number of elements to allocate + *  + * Allocates @n_structs elements of type @struct_type. + * The returned pointer is cast to a pointer to the given type. + * If @n_structs is 0 it returns %NULL. + * Care is taken to avoid overflow when calculating the size of the allocated block. + *  + * Since the returned pointer is already casted to the right type, + * it is normally unnecessary to cast it explicitly, and doing + * so might hide memory allocation errors. + *  + * Returns: a pointer to the allocated memory, cast to a pointer to @struct_type + */ +#define g_new(struct_type, n_structs)			_G_NEW (struct_type, n_structs, malloc) +/** + * g_new0: + * @struct_type: the type of the elements to allocate. + * @n_structs: the number of elements to allocate. + *  + * Allocates @n_structs elements of type @struct_type, initialized to 0's. + * The returned pointer is cast to a pointer to the given type. + * If @n_structs is 0 it returns %NULL. + * Care is taken to avoid overflow when calculating the size of the allocated block. + *  + * Since the returned pointer is already casted to the right type, + * it is normally unnecessary to cast it explicitly, and doing + * so might hide memory allocation errors. + *  + * Returns: a pointer to the allocated memory, cast to a pointer to @struct_type. + */ +#define g_new0(struct_type, n_structs)			_G_NEW (struct_type, n_structs, malloc0) +/** + * g_renew: + * @struct_type: the type of the elements to allocate + * @mem: the currently allocated memory + * @n_structs: the number of elements to allocate + *  + * Reallocates the memory pointed to by @mem, so that it now has space for + * @n_structs elements of type @struct_type. It returns the new address of + * the memory, which may have been moved. + * Care is taken to avoid overflow when calculating the size of the allocated block. + *  + * Returns: a pointer to the new allocated memory, cast to a pointer to @struct_type + */ +#define g_renew(struct_type, mem, n_structs)		_G_RENEW (struct_type, mem, n_structs, realloc) +/** + * g_try_new: + * @struct_type: the type of the elements to allocate + * @n_structs: the number of elements to allocate + *  + * Attempts to allocate @n_structs elements of type @struct_type, and returns + * %NULL on failure. Contrast with g_new(), which aborts the program on failure. + * The returned pointer is cast to a pointer to the given type. + * The function returns %NULL when @n_structs is 0 of if an overflow occurs. + *  + * Since: 2.8 + * Returns: a pointer to the allocated memory, cast to a pointer to @struct_type + */ +#define g_try_new(struct_type, n_structs)		_G_NEW (struct_type, n_structs, try_malloc) +/** + * g_try_new0: + * @struct_type: the type of the elements to allocate + * @n_structs: the number of elements to allocate + *  + * Attempts to allocate @n_structs elements of type @struct_type, initialized + * to 0's, and returns %NULL on failure. Contrast with g_new0(), which aborts + * the program on failure. + * The returned pointer is cast to a pointer to the given type. + * The function returns %NULL when @n_structs is 0 of if an overflow occurs. + *  + * Since: 2.8 + * Returns: a pointer to the allocated memory, cast to a pointer to @struct_type + */ +#define g_try_new0(struct_type, n_structs)		_G_NEW (struct_type, n_structs, try_malloc0) +/** + * g_try_renew: + * @struct_type: the type of the elements to allocate + * @mem: the currently allocated memory + * @n_structs: the number of elements to allocate + *  + * Attempts to reallocate the memory pointed to by @mem, so that it now has + * space for @n_structs elements of type @struct_type, and returns %NULL on + * failure. Contrast with g_renew(), which aborts the program on failure. + * It returns the new address of the memory, which may have been moved. + * The function returns %NULL if an overflow occurs. + *  + * Since: 2.8 + * Returns: a pointer to the new allocated memory, cast to a pointer to @struct_type + */ +#define g_try_renew(struct_type, mem, n_structs)	_G_RENEW (struct_type, mem, n_structs, try_realloc) + + +/* Memory allocation virtualization for debugging purposes + * g_mem_set_vtable() has to be the very first GLib function called + * if being used + */ +struct _GMemVTable { +  gpointer (*malloc)      (gsize    n_bytes); +  gpointer (*realloc)     (gpointer mem, +			   gsize    n_bytes); +  void     (*free)        (gpointer mem); +  /* optional; set to NULL if not used ! */ +  gpointer (*calloc)      (gsize    n_blocks, +			   gsize    n_block_bytes); +  gpointer (*try_malloc)  (gsize    n_bytes); +  gpointer (*try_realloc) (gpointer mem, +			   gsize    n_bytes); +}; +void	 g_mem_set_vtable (GMemVTable	*vtable); +gboolean g_mem_is_system_malloc (void); + +GLIB_VAR gboolean g_mem_gc_friendly; + +/* Memory profiler and checker, has to be enabled via g_mem_set_vtable() + */ +GLIB_VAR GMemVTable	*glib_mem_profiler_table; +void	g_mem_profile	(void); + + +/* deprecated memchunks and allocators */ +#if !defined (G_DISABLE_DEPRECATED) || defined (GTK_COMPILATION) || defined (GDK_COMPILATION) +typedef struct _GAllocator GAllocator; +typedef struct _GMemChunk  GMemChunk; +#define g_mem_chunk_create(type, pre_alloc, alloc_type)	( \ +  g_mem_chunk_new (#type " mem chunks (" #pre_alloc ")", \ +		   sizeof (type), \ +		   sizeof (type) * (pre_alloc), \ +		   (alloc_type)) \ +) +#define g_chunk_new(type, chunk)	( \ +  (type *) g_mem_chunk_alloc (chunk) \ +) +#define g_chunk_new0(type, chunk)	( \ +  (type *) g_mem_chunk_alloc0 (chunk) \ +) +#define g_chunk_free(mem, mem_chunk)	G_STMT_START { \ +  g_mem_chunk_free ((mem_chunk), (mem)); \ +} G_STMT_END +#define G_ALLOC_ONLY	  1 +#define G_ALLOC_AND_FREE  2 +GMemChunk* g_mem_chunk_new     (const gchar *name, +				gint         atom_size, +				gsize        area_size, +				gint         type); +void       g_mem_chunk_destroy (GMemChunk   *mem_chunk); +gpointer   g_mem_chunk_alloc   (GMemChunk   *mem_chunk); +gpointer   g_mem_chunk_alloc0  (GMemChunk   *mem_chunk); +void       g_mem_chunk_free    (GMemChunk   *mem_chunk, +				gpointer     mem); +void       g_mem_chunk_clean   (GMemChunk   *mem_chunk); +void       g_mem_chunk_reset   (GMemChunk   *mem_chunk); +void       g_mem_chunk_print   (GMemChunk   *mem_chunk); +void       g_mem_chunk_info    (void); +void	   g_blow_chunks       (void); +GAllocator*g_allocator_new     (const gchar  *name, +				guint         n_preallocs); +void       g_allocator_free    (GAllocator   *allocator); +#define	G_ALLOCATOR_LIST       (1) +#define	G_ALLOCATOR_SLIST      (2) +#define	G_ALLOCATOR_NODE       (3) +#endif /* G_DISABLE_DEPRECATED */ + +G_END_DECLS + +#endif /* __G_MEM_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gmessages.h b/protocols/Sametime/src/glib/include/glib/gmessages.h new file mode 100644 index 0000000000..9acaec6375 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gmessages.h @@ -0,0 +1,343 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_MESSAGES_H__ +#define __G_MESSAGES_H__ + +#include <stdarg.h> +#include <glib/gtypes.h> +#include <glib/gmacros.h> + +/* Suppress warnings when GCC is in -pedantic mode and not -std=c99 + */ +#if (__GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)) +#pragma GCC system_header +#endif + +G_BEGIN_DECLS + +/* calculate a string size, guaranteed to fit format + args. + */ +gsize	g_printf_string_upper_bound (const gchar* format, +				     va_list	  args); + +/* Log level shift offset for user defined + * log levels (0-7 are used by GLib). + */ +#define G_LOG_LEVEL_USER_SHIFT  (8) + +/* Glib log levels and flags. + */ +typedef enum +{ +  /* log flags */ +  G_LOG_FLAG_RECURSION          = 1 << 0, +  G_LOG_FLAG_FATAL              = 1 << 1, + +  /* GLib log levels */ +  G_LOG_LEVEL_ERROR             = 1 << 2,       /* always fatal */ +  G_LOG_LEVEL_CRITICAL          = 1 << 3, +  G_LOG_LEVEL_WARNING           = 1 << 4, +  G_LOG_LEVEL_MESSAGE           = 1 << 5, +  G_LOG_LEVEL_INFO              = 1 << 6, +  G_LOG_LEVEL_DEBUG             = 1 << 7, + +  G_LOG_LEVEL_MASK              = ~(G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL) +} GLogLevelFlags; + +/* GLib log levels that are considered fatal by default */ +#define G_LOG_FATAL_MASK        (G_LOG_FLAG_RECURSION | G_LOG_LEVEL_ERROR) + +typedef void            (*GLogFunc)             (const gchar   *log_domain, +                                                 GLogLevelFlags log_level, +                                                 const gchar   *message, +                                                 gpointer       user_data); + +/* Logging mechanism + */ +guint           g_log_set_handler       (const gchar    *log_domain, +                                         GLogLevelFlags  log_levels, +                                         GLogFunc        log_func, +                                         gpointer        user_data); +void            g_log_remove_handler    (const gchar    *log_domain, +                                         guint           handler_id); +void            g_log_default_handler   (const gchar    *log_domain, +                                         GLogLevelFlags  log_level, +                                         const gchar    *message, +                                         gpointer        unused_data); +GLogFunc        g_log_set_default_handler (GLogFunc      log_func, +					   gpointer      user_data); +void            g_log                   (const gchar    *log_domain, +                                         GLogLevelFlags  log_level, +                                         const gchar    *format, +                                         ...) G_GNUC_PRINTF (3, 4); +void            g_logv                  (const gchar    *log_domain, +                                         GLogLevelFlags  log_level, +                                         const gchar    *format, +                                         va_list         args); +GLogLevelFlags  g_log_set_fatal_mask    (const gchar    *log_domain, +                                         GLogLevelFlags  fatal_mask); +GLogLevelFlags  g_log_set_always_fatal  (GLogLevelFlags  fatal_mask); + +/* internal */ +G_GNUC_INTERNAL void	_g_log_fallback_handler	(const gchar   *log_domain, +						 GLogLevelFlags log_level, +						 const gchar   *message, +						 gpointer       unused_data); + +/* Internal functions, used to implement the following macros */ +void g_return_if_fail_warning (const char *log_domain, +			       const char *pretty_function, +			       const char *expression); +void g_warn_message           (const char     *domain, +                               const char     *file, +                               int             line, +                               const char     *func, +                               const char     *warnexpr); +#ifndef G_DISABLE_DEPRECATED +void g_assert_warning         (const char *log_domain, +			       const char *file, +			       const int   line, +		               const char *pretty_function, +		               const char *expression) G_GNUC_NORETURN; +#endif /* !G_DISABLE_DEPRECATED */ + + +#ifndef G_LOG_DOMAIN +#define G_LOG_DOMAIN    ((gchar*) 0) +#endif  /* G_LOG_DOMAIN */ +#ifdef G_HAVE_ISO_VARARGS +/* for(;;) ; so that GCC knows that control doesn't go past g_error(). + * Put space before ending semicolon to avoid C++ build warnings. + */ +#define g_error(...)  G_STMT_START {                 \ +                        g_log (G_LOG_DOMAIN,         \ +                               G_LOG_LEVEL_ERROR,    \ +                               __VA_ARGS__);         \ +                        for (;;) ;                   \ +                      } G_STMT_END +                         +#define g_message(...)  g_log (G_LOG_DOMAIN,         \ +                               G_LOG_LEVEL_MESSAGE,  \ +                               __VA_ARGS__) +#define g_critical(...) g_log (G_LOG_DOMAIN,         \ +                               G_LOG_LEVEL_CRITICAL, \ +                               __VA_ARGS__) +#define g_warning(...)  g_log (G_LOG_DOMAIN,         \ +                               G_LOG_LEVEL_WARNING,  \ +                               __VA_ARGS__) +#define g_debug(...)    g_log (G_LOG_DOMAIN,         \ +                               G_LOG_LEVEL_DEBUG,    \ +                               __VA_ARGS__) +#elif defined(G_HAVE_GNUC_VARARGS) +#define g_error(format...)    G_STMT_START {                 \ +                                g_log (G_LOG_DOMAIN,         \ +                                       G_LOG_LEVEL_ERROR,    \ +                                       format);              \ +                                for (;;) ;                   \ +                              } G_STMT_END +                               +#define g_message(format...)    g_log (G_LOG_DOMAIN,         \ +                                       G_LOG_LEVEL_MESSAGE,  \ +                                       format) +#define g_critical(format...)   g_log (G_LOG_DOMAIN,         \ +                                       G_LOG_LEVEL_CRITICAL, \ +                                       format) +#define g_warning(format...)    g_log (G_LOG_DOMAIN,         \ +                                       G_LOG_LEVEL_WARNING,  \ +                                       format) +#define g_debug(format...)      g_log (G_LOG_DOMAIN,         \ +                                       G_LOG_LEVEL_DEBUG,    \ +                                       format) +#else   /* no varargs macros */ +static void +g_error (const gchar *format, +         ...) +{ +  va_list args; +  va_start (args, format); +  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, format, args); +  va_end (args); + +  for(;;) ; +} +static void +g_message (const gchar *format, +           ...) +{ +  va_list args; +  va_start (args, format); +  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, args); +  va_end (args); +} +static void +g_critical (const gchar *format, +            ...) +{ +  va_list args; +  va_start (args, format); +  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, format, args); +  va_end (args); +} +static void +g_warning (const gchar *format, +           ...) +{ +  va_list args; +  va_start (args, format); +  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, format, args); +  va_end (args); +} +static void +g_debug (const gchar *format, +         ...) +{ +  va_list args; +  va_start (args, format); +  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format, args); +  va_end (args); +} +#endif  /* !__GNUC__ */ + +typedef void    (*GPrintFunc)           (const gchar    *string); +void            g_print                 (const gchar    *format, +                                         ...) G_GNUC_PRINTF (1, 2); +GPrintFunc      g_set_print_handler     (GPrintFunc      func); +void            g_printerr              (const gchar    *format, +                                         ...) G_GNUC_PRINTF (1, 2); +GPrintFunc      g_set_printerr_handler  (GPrintFunc      func); + + +/* Provide macros for graceful error handling. + * The "return" macros will return from the current function. + * Two different definitions are given for the macros in + * order to support gcc's __PRETTY_FUNCTION__ capability. + */ + +#define g_warn_if_reached()     do { g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, NULL); } while (0) +#define g_warn_if_fail(expr)    do { if G_LIKELY (expr) ; else \ +                                       g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, #expr); } while (0) + +#ifdef G_DISABLE_CHECKS + +#define g_return_if_fail(expr)			G_STMT_START{ (void)0; }G_STMT_END +#define g_return_val_if_fail(expr,val)		G_STMT_START{ (void)0; }G_STMT_END +#define g_return_if_reached()			G_STMT_START{ return; }G_STMT_END +#define g_return_val_if_reached(val)		G_STMT_START{ return (val); }G_STMT_END + +#else /* !G_DISABLE_CHECKS */ + +#ifdef __GNUC__ + +#define g_return_if_fail(expr)		G_STMT_START{			\ +     if G_LIKELY(expr) { } else       					\ +       {								\ +	 g_return_if_fail_warning (G_LOG_DOMAIN,			\ +		                   __PRETTY_FUNCTION__,		        \ +		                   #expr);				\ +	 return;							\ +       };				}G_STMT_END + +#define g_return_val_if_fail(expr,val)	G_STMT_START{			\ +     if G_LIKELY(expr) { } else						\ +       {								\ +	 g_return_if_fail_warning (G_LOG_DOMAIN,			\ +		                   __PRETTY_FUNCTION__,		        \ +		                   #expr);				\ +	 return (val);							\ +       };				}G_STMT_END + +#define g_return_if_reached()		G_STMT_START{			\ +     g_log (G_LOG_DOMAIN,						\ +	    G_LOG_LEVEL_CRITICAL,					\ +	    "file %s: line %d (%s): should not be reached",		\ +	    __FILE__,							\ +	    __LINE__,							\ +	    __PRETTY_FUNCTION__);					\ +     return;				}G_STMT_END + +#define g_return_val_if_reached(val)	G_STMT_START{			\ +     g_log (G_LOG_DOMAIN,						\ +	    G_LOG_LEVEL_CRITICAL,					\ +	    "file %s: line %d (%s): should not be reached",		\ +	    __FILE__,							\ +	    __LINE__,							\ +	    __PRETTY_FUNCTION__);					\ +     return (val);			}G_STMT_END + +#else /* !__GNUC__ */ + +#define g_return_if_fail(expr)		G_STMT_START{		\ +     if (expr) { } else						\ +       {							\ +	 g_log (G_LOG_DOMAIN,					\ +		G_LOG_LEVEL_CRITICAL,				\ +		"file %s: line %d: assertion `%s' failed",	\ +		__FILE__,					\ +		__LINE__,					\ +		#expr);						\ +	 return;						\ +       };				}G_STMT_END + +#define g_return_val_if_fail(expr, val)	G_STMT_START{		\ +     if (expr) { } else						\ +       {							\ +	 g_log (G_LOG_DOMAIN,					\ +		G_LOG_LEVEL_CRITICAL,				\ +		"file %s: line %d: assertion `%s' failed",	\ +		__FILE__,					\ +		__LINE__,					\ +		#expr);						\ +	 return (val);						\ +       };				}G_STMT_END + +#define g_return_if_reached()		G_STMT_START{		\ +     g_log (G_LOG_DOMAIN,					\ +	    G_LOG_LEVEL_CRITICAL,				\ +	    "file %s: line %d: should not be reached",		\ +	    __FILE__,						\ +	    __LINE__);						\ +     return;				}G_STMT_END + +#define g_return_val_if_reached(val)	G_STMT_START{		\ +     g_log (G_LOG_DOMAIN,					\ +	    G_LOG_LEVEL_CRITICAL,				\ +	    "file %s: line %d: should not be reached",		\ +	    __FILE__,						\ +	    __LINE__);						\ +     return (val);			}G_STMT_END + +#endif /* !__GNUC__ */ + +#endif /* !G_DISABLE_CHECKS */ + +G_END_DECLS + +#endif /* __G_MESSAGES_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gnode.h b/protocols/Sametime/src/glib/include/glib/gnode.h new file mode 100644 index 0000000000..205d47c763 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gnode.h @@ -0,0 +1,290 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_NODE_H__ +#define __G_NODE_H__ + +#include <glib/gmem.h> + +G_BEGIN_DECLS + +typedef struct _GNode		GNode; + +/* Tree traverse flags */ +typedef enum +{ +  G_TRAVERSE_LEAVES     = 1 << 0, +  G_TRAVERSE_NON_LEAVES = 1 << 1, +  G_TRAVERSE_ALL        = G_TRAVERSE_LEAVES | G_TRAVERSE_NON_LEAVES, +  G_TRAVERSE_MASK       = 0x03, +  G_TRAVERSE_LEAFS      = G_TRAVERSE_LEAVES, +  G_TRAVERSE_NON_LEAFS  = G_TRAVERSE_NON_LEAVES +} GTraverseFlags; + +/* Tree traverse orders */ +typedef enum +{ +  G_IN_ORDER, +  G_PRE_ORDER, +  G_POST_ORDER, +  G_LEVEL_ORDER +} GTraverseType; + +typedef gboolean	(*GNodeTraverseFunc)	(GNode	       *node, +						 gpointer	data); +typedef void		(*GNodeForeachFunc)	(GNode	       *node, +						 gpointer	data); + +/** + * GCopyFunc: + * @src: A pointer to the data which should be copied + * @data: Additional data + * + * A function of this signature is used to copy the node data  + * when doing a deep-copy of a tree. + * + * Returns: A pointer to the copy + * + * Since: 2.4 + */ +typedef gpointer	(*GCopyFunc)            (gconstpointer  src, +                                                 gpointer       data); + +/* N-way tree implementation + */ +struct _GNode +{ +  gpointer data; +  GNode	  *next; +  GNode	  *prev; +  GNode	  *parent; +  GNode	  *children; +}; + +/** + * G_NODE_IS_ROOT: + * @node: a #GNode + * + * Returns %TRUE if a #GNode is the root of a tree. + * + * Returns: %TRUE if the #GNode is the root of a tree  + *     (i.e. it has no parent or siblings) + */ +#define	 G_NODE_IS_ROOT(node)	(((GNode*) (node))->parent == NULL && \ +				 ((GNode*) (node))->prev == NULL && \ +				 ((GNode*) (node))->next == NULL) + +/** + * G_NODE_IS_LEAF: + * @node: a #GNode + * + * Returns %TRUE if a #GNode is a leaf node. + * + * Returns: %TRUE if the #GNode is a leaf node  + *     (i.e. it has no children) + */ +#define	 G_NODE_IS_LEAF(node)	(((GNode*) (node))->children == NULL) + +GNode*	 g_node_new		(gpointer	   data); +void	 g_node_destroy		(GNode		  *root); +void	 g_node_unlink		(GNode		  *node); +GNode*   g_node_copy_deep       (GNode            *node, +				 GCopyFunc         copy_func, +				 gpointer          data); +GNode*   g_node_copy            (GNode            *node); +GNode*	 g_node_insert		(GNode		  *parent, +				 gint		   position, +				 GNode		  *node); +GNode*	 g_node_insert_before	(GNode		  *parent, +				 GNode		  *sibling, +				 GNode		  *node); +GNode*   g_node_insert_after    (GNode            *parent, +				 GNode            *sibling, +				 GNode            *node);  +GNode*	 g_node_prepend		(GNode		  *parent, +				 GNode		  *node); +guint	 g_node_n_nodes		(GNode		  *root, +				 GTraverseFlags	   flags); +GNode*	 g_node_get_root	(GNode		  *node); +gboolean g_node_is_ancestor	(GNode		  *node, +				 GNode		  *descendant); +guint	 g_node_depth		(GNode		  *node); +GNode*	 g_node_find		(GNode		  *root, +				 GTraverseType	   order, +				 GTraverseFlags	   flags, +				 gpointer	   data); + +/* convenience macros */ +/** + * g_node_append: + * @parent: the #GNode to place the new #GNode under + * @node: the #GNode to insert + * + * Inserts a #GNode as the last child of the given parent. + * + * Returns: the inserted #GNode + */ +#define g_node_append(parent, node)				\ +     g_node_insert_before ((parent), NULL, (node)) + +/** + * g_node_insert_data: + * @parent: the #GNode to place the new #GNode under + * @position: the position to place the new #GNode at. If position is -1,  + *     the new #GNode is inserted as the last child of @parent + * @data: the data for the new #GNode + * + * Inserts a new #GNode at the given position. + * + * Returns: the new #GNode + */ +#define	g_node_insert_data(parent, position, data)		\ +     g_node_insert ((parent), (position), g_node_new (data)) + +/** + * g_node_insert_data_before: + * @parent: the #GNode to place the new #GNode under + * @sibling: the sibling #GNode to place the new #GNode before + * @data: the data for the new #GNode + * + * Inserts a new #GNode before the given sibling. + * + * Returns: the new #GNode + */ +#define	g_node_insert_data_before(parent, sibling, data)	\ +     g_node_insert_before ((parent), (sibling), g_node_new (data)) + +/** + * g_node_prepend_data: + * @parent: the #GNode to place the new #GNode under + * @data: the data for the new #GNode + * + * Inserts a new #GNode as the first child of the given parent. + * + * Returns: the new #GNode + */ +#define	g_node_prepend_data(parent, data)			\ +     g_node_prepend ((parent), g_node_new (data)) + +/** + * g_node_append_data: + * @parent: the #GNode to place the new #GNode under + * @data: the data for the new #GNode + * + * Inserts a new #GNode as the last child of the given parent. + * + * Returns: the new #GNode + */ +#define	g_node_append_data(parent, data)			\ +     g_node_insert_before ((parent), NULL, g_node_new (data)) + +/* traversal function, assumes that `node' is root + * (only traverses `node' and its subtree). + * this function is just a high level interface to + * low level traversal functions, optimized for speed. + */ +void	 g_node_traverse	(GNode		  *root, +				 GTraverseType	   order, +				 GTraverseFlags	   flags, +				 gint		   max_depth, +				 GNodeTraverseFunc func, +				 gpointer	   data); + +/* return the maximum tree height starting with `node', this is an expensive + * operation, since we need to visit all nodes. this could be shortened by + * adding `guint height' to struct _GNode, but then again, this is not very + * often needed, and would make g_node_insert() more time consuming. + */ +guint	 g_node_max_height	 (GNode *root); + +void	 g_node_children_foreach (GNode		  *node, +				  GTraverseFlags   flags, +				  GNodeForeachFunc func, +				  gpointer	   data); +void	 g_node_reverse_children (GNode		  *node); +guint	 g_node_n_children	 (GNode		  *node); +GNode*	 g_node_nth_child	 (GNode		  *node, +				  guint		   n); +GNode*	 g_node_last_child	 (GNode		  *node); +GNode*	 g_node_find_child	 (GNode		  *node, +				  GTraverseFlags   flags, +				  gpointer	   data); +gint	 g_node_child_position	 (GNode		  *node, +				  GNode		  *child); +gint	 g_node_child_index	 (GNode		  *node, +				  gpointer	   data); + +GNode*	 g_node_first_sibling	 (GNode		  *node); +GNode*	 g_node_last_sibling	 (GNode		  *node); + +/** + * g_node_prev_sibling: + * @node: a #GNode + * + * Gets the previous sibling of a #GNode. + * + * Returns: the previous sibling of @node, or %NULL if @node is the first + *     node or %NULL + */ +#define	 g_node_prev_sibling(node)	((node) ? \ +					 ((GNode*) (node))->prev : NULL) + +/** + * g_node_next_sibling: + * @node: a #GNode + * + * Gets the next sibling of a #GNode. + * + * Returns: the next sibling of @node, or %NULL if @node is the last node + *     or %NULL + */ +#define	 g_node_next_sibling(node)	((node) ? \ +					 ((GNode*) (node))->next : NULL) + +/** + * g_node_first_child: + * @node: a #GNode + * + * Gets the first child of a #GNode. + * + * Returns: the first child of @node, or %NULL if @node is %NULL  + *     or has no children + */ +#define	 g_node_first_child(node)	((node) ? \ +					 ((GNode*) (node))->children : NULL) + +#ifndef G_DISABLE_DEPRECATED +void     g_node_push_allocator  (gpointer          dummy); +void     g_node_pop_allocator   (void); +#endif + +G_END_DECLS + +#endif /* __G_NODE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/goption.h b/protocols/Sametime/src/glib/include/glib/goption.h new file mode 100644 index 0000000000..557d8f7130 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/goption.h @@ -0,0 +1,370 @@ +/* goption.h - Option parser + * + *  Copyright (C) 2004  Anders Carlsson <andersca@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_OPTION_H__ +#define __G_OPTION_H__ + +#include <glib/gerror.h> +#include <glib/gquark.h> + +G_BEGIN_DECLS + +/** + * GOptionContext: + *  + * A <structname>GOptionContext</structname> struct defines which options + * are accepted by the commandline option parser. The struct has only private  + * fields and should not be directly accessed. + */ +typedef struct _GOptionContext GOptionContext; + +/** + * GOptionGroup: + * + * A <structname>GOptionGroup</structname> struct defines the options in a single + * group. The struct has only private fields and should not be directly accessed. + * + * All options in a group share the same translation function. Libraries which + * need to parse commandline options are expected to provide a function for + * getting a <structname>GOptionGroup</structname> holding their options, which + * the application can then add to its #GOptionContext. + */ +typedef struct _GOptionGroup   GOptionGroup; +typedef struct _GOptionEntry   GOptionEntry; + +/** + * GOptionFlags: + * @G_OPTION_FLAG_HIDDEN: The option doesn't appear in <option>--help</option> + *  output. + * @G_OPTION_FLAG_IN_MAIN: The option appears in the main section of the + *  <option>--help</option> output, even if it is defined in a group. + * @G_OPTION_FLAG_REVERSE: For options of the %G_OPTION_ARG_NONE kind, this flag + *  indicates that the sense of the option is reversed. + * @G_OPTION_FLAG_NO_ARG: For options of the %G_OPTION_ARG_CALLBACK kind, + *  this flag indicates that the callback does not take any argument + *  (like a %G_OPTION_ARG_NONE option). Since 2.8 + * @G_OPTION_FLAG_FILENAME: For options of the %G_OPTION_ARG_CALLBACK + *  kind, this flag indicates that the argument should be passed to the + *  callback in the GLib filename encoding rather than UTF-8. Since 2.8 + * @G_OPTION_FLAG_OPTIONAL_ARG: For options of the %G_OPTION_ARG_CALLBACK  + *  kind, this flag indicates that the argument supply is optional. If no argument + *  is given then data of %GOptionParseFunc will be set to NULL. Since 2.8 + * @G_OPTION_FLAG_NOALIAS: This flag turns off the automatic conflict resolution + *  which prefixes long option names with <literal>groupname-</literal> if  + *  there is a conflict. This option should only be used in situations where + *  aliasing is necessary to model some legacy commandline interface. It is + *  not safe to use this option, unless all option groups are under your  + *  direct control. Since 2.8. + *  + * Flags which modify individual options. + */ +typedef enum +{ +  G_OPTION_FLAG_HIDDEN		= 1 << 0, +  G_OPTION_FLAG_IN_MAIN		= 1 << 1, +  G_OPTION_FLAG_REVERSE		= 1 << 2, +  G_OPTION_FLAG_NO_ARG		= 1 << 3, +  G_OPTION_FLAG_FILENAME	= 1 << 4, +  G_OPTION_FLAG_OPTIONAL_ARG    = 1 << 5, +  G_OPTION_FLAG_NOALIAS	        = 1 << 6 +} GOptionFlags; + +/** + * GOptionArg: + * @G_OPTION_ARG_NONE: No extra argument. This is useful for simple flags. + * @G_OPTION_ARG_STRING: The option takes a string argument. + * @G_OPTION_ARG_INT: The option takes an integer argument. + * @G_OPTION_ARG_CALLBACK: The option provides a callback to parse the + *  extra argument. + * @G_OPTION_ARG_FILENAME: The option takes a filename as argument. + * @G_OPTION_ARG_STRING_ARRAY: The option takes a string argument, multiple + *  uses of the option are collected into an array of strings. + * @G_OPTION_ARG_FILENAME_ARRAY: The option takes a filename as argument,  + *  multiple uses of the option are collected into an array of strings. + * @G_OPTION_ARG_DOUBLE: The option takes a double argument. The argument + *  can be formatted either for the user's locale or for the "C" locale. Since 2.12 + * @G_OPTION_ARG_INT64: The option takes a 64-bit integer. Like %G_OPTION_ARG_INT + *  but for larger numbers. The number can be in decimal base, or in hexadecimal + *  (when prefixed with <literal>0x</literal>, for example, <literal>0xffffffff</literal>). + *  Since 2.12 + *  + * The #GOptionArg enum values determine which type of extra argument the + * options expect to find. If an option expects an extra argument, it + * can be specified in several ways; with a short option: + * <option>-x arg</option>, with a long option: <option>--name arg</option> + * or combined in a single argument: <option>--name=arg</option>. + */ +typedef enum +{ +  G_OPTION_ARG_NONE, +  G_OPTION_ARG_STRING, +  G_OPTION_ARG_INT, +  G_OPTION_ARG_CALLBACK, +  G_OPTION_ARG_FILENAME, +  G_OPTION_ARG_STRING_ARRAY, +  G_OPTION_ARG_FILENAME_ARRAY, +  G_OPTION_ARG_DOUBLE, +  G_OPTION_ARG_INT64 +} GOptionArg; + +/** + * GOptionArgFunc: + * @option_name: The name of the option being parsed. This will be either a  + *  single dash followed by a single letter (for a short name) or two dashes + *  followed by a long option name. + * @value: The value to be parsed. + * @data: User data added to the #GOptionGroup containing the option when it + *  was created with g_option_group_new() + * @error: A return location for errors. The error code %G_OPTION_ERROR_FAILED + *  is intended to be used for errors in #GOptionArgFunc callbacks. + *  + * The type of function to be passed as callback for %G_OPTION_ARG_CALLBACK + * options. + *  + * Returns: %TRUE if the option was successfully parsed, %FALSE if an error  + *  occurred, in which case @error should be set with g_set_error() + */ +typedef gboolean (*GOptionArgFunc) (const gchar    *option_name, +				    const gchar    *value, +				    gpointer        data, +				    GError        **error); + +/** + * GOptionParseFunc: + * @context: The active #GOptionContext + * @group: The group to which the function belongs + * @data: User data added to the #GOptionGroup containing the option when it + *  was created with g_option_group_new() + * @error: A return location for error details + *  + * The type of function that can be called before and after parsing.  + *  + * Returns: %TRUE if the function completed successfully, %FALSE if an error  + *  occurred, in which case @error should be set with g_set_error() + */ +typedef gboolean (*GOptionParseFunc) (GOptionContext *context, +				      GOptionGroup   *group, +				      gpointer	      data, +				      GError        **error); + +/** + * GOptionErrorFunc: + * @context: The active #GOptionContext + * @group: The group to which the function belongs + * @data: User data added to the #GOptionGroup containing the option when it + *  was created with g_option_group_new() + * @error: The #GError containing details about the parse error + *  + * The type of function to be used as callback when a parse error occurs. + */ +typedef void (*GOptionErrorFunc) (GOptionContext *context, +				  GOptionGroup   *group, +				  gpointer        data, +				  GError        **error); + +/** + * G_OPTION_ERROR: + *  + * Error domain for option parsing. Errors in this domain will + * be from the #GOptionError enumeration. See #GError for information on  + * error domains. + */ +#define G_OPTION_ERROR (g_option_error_quark ()) + +/** + * GOptionError: + * @G_OPTION_ERROR_UNKNOWN_OPTION: An option was not known to the parser. + *  This error will only be reported, if the parser hasn't been instructed + *  to ignore unknown options, see g_option_context_set_ignore_unknown_options(). + * @G_OPTION_ERROR_BAD_VALUE: A value couldn't be parsed. + * @G_OPTION_ERROR_FAILED: A #GOptionArgFunc callback failed. + *  + * Error codes returned by option parsing. + */ +typedef enum +{ +  G_OPTION_ERROR_UNKNOWN_OPTION, +  G_OPTION_ERROR_BAD_VALUE, +  G_OPTION_ERROR_FAILED +} GOptionError; + +GQuark g_option_error_quark (void); + +/** + * GOptionEntry: + * @long_name: The long name of an option can be used to specify it + *  in a commandline as --<replaceable>long_name</replaceable>. Every + *  option must have a long name. To resolve conflicts if multiple + *  option groups contain the same long name, it is also possible to + *  specify the option as  + *  --<replaceable>groupname</replaceable>-<replaceable>long_name</replaceable>. + * @short_name: If an option has a short name, it can be specified + *  -<replaceable>short_name</replaceable> in a commandline. @short_name must be  + *  a printable ASCII character different from '-', or zero if the option has no + *  short name. + * @flags: Flags from #GOptionFlags. + * @arg: The type of the option, as a #GOptionArg. + * @arg_data: If the @arg type is %G_OPTION_ARG_CALLBACK, then @arg_data must  + *  point to a #GOptionArgFunc callback function, which will be called to handle  + *  the extra argument. Otherwise, @arg_data is a pointer to a location to store  + *  the value, the required type of the location depends on the @arg type: + *  <variablelist> + *  <varlistentry> + *  <term>%G_OPTION_ARG_NONE</term> + *  <listitem><para>%gboolean</para></listitem> + *  </varlistentry> + *  <varlistentry> + *  <term>%G_OPTION_ARG_STRING</term> + *  <listitem><para>%gchar*</para></listitem> + *  </varlistentry> + *  <varlistentry> + *  <term>%G_OPTION_ARG_INT</term> + *  <listitem><para>%gint</para></listitem> + *  </varlistentry> + *  <varlistentry> + *  <term>%G_OPTION_ARG_FILENAME</term> + *  <listitem><para>%gchar*</para></listitem> + *  </varlistentry> + *  <varlistentry> + *  <term>%G_OPTION_ARG_STRING_ARRAY</term> + *  <listitem><para>%gchar**</para></listitem> + *  </varlistentry> + *  <varlistentry> + *  <term>%G_OPTION_ARG_FILENAME_ARRAY</term> + *  <listitem><para>%gchar**</para></listitem> + *  </varlistentry> + *  <varlistentry> + *  <term>%G_OPTION_ARG_DOUBLE</term> + *  <listitem><para>%gdouble</para></listitem> + *  </varlistentry> + *  </variablelist> + *  If @arg type is %G_OPTION_ARG_STRING or %G_OPTION_ARG_FILENAME the location + *  will contain a newly allocated string if the option was given. That string + *  needs to be freed by the callee using g_free(). Likewise if @arg type is + *  %G_OPTION_ARG_STRING_ARRAY or %G_OPTION_ARG_FILENAME_ARRAY, the data should + *  be freed using g_strfreev(). + * @description: the description for the option in <option>--help</option> + *  output. The @description is translated using the @translate_func of the + *  group, see g_option_group_set_translation_domain(). + * @arg_description: The placeholder to use for the extra argument parsed + *  by the option in <option>--help</option> + *  output. The @arg_description is translated using the @translate_func of the + *  group, see g_option_group_set_translation_domain(). + *  + * A <structname>GOptionEntry</structname> defines a single option. + * To have an effect, they must be added to a #GOptionGroup with + * g_option_context_add_main_entries() or g_option_group_add_entries(). + */ +struct _GOptionEntry +{ +  const gchar *long_name; +  gchar        short_name; +  gint         flags; + +  GOptionArg   arg; +  gpointer     arg_data; +   +  const gchar *description; +  const gchar *arg_description; +}; + +/** + * G_OPTION_REMAINING: + *  + * If a long option in the main group has this name, it is not treated as a  + * regular option. Instead it collects all non-option arguments which would + * otherwise be left in <literal>argv</literal>. The option must be of type + * %G_OPTION_ARG_CALLBACK, %G_OPTION_ARG_STRING_ARRAY + * or %G_OPTION_ARG_FILENAME_ARRAY. + *  + *  + * Using #G_OPTION_REMAINING instead of simply scanning <literal>argv</literal> + * for leftover arguments has the advantage that GOption takes care of  + * necessary encoding conversions for strings or filenames. + *  + * Since: 2.6 + */ +#define G_OPTION_REMAINING "" + +GOptionContext *g_option_context_new              (const gchar         *parameter_string); +void            g_option_context_set_summary      (GOptionContext      *context, +                                                   const gchar         *summary); +G_CONST_RETURN gchar *g_option_context_get_summary (GOptionContext     *context); +void            g_option_context_set_description  (GOptionContext      *context, +                                                   const gchar         *description); +G_CONST_RETURN gchar *g_option_context_get_description (GOptionContext     *context); +void            g_option_context_free             (GOptionContext      *context); +void		g_option_context_set_help_enabled (GOptionContext      *context, +						   gboolean		help_enabled); +gboolean	g_option_context_get_help_enabled (GOptionContext      *context); +void		g_option_context_set_ignore_unknown_options (GOptionContext *context, +							     gboolean	     ignore_unknown); +gboolean        g_option_context_get_ignore_unknown_options (GOptionContext *context); + +void            g_option_context_add_main_entries (GOptionContext      *context, +						   const GOptionEntry  *entries, +						   const gchar         *translation_domain); +gboolean        g_option_context_parse            (GOptionContext      *context, +						   gint                *argc, +						   gchar             ***argv, +						   GError             **error); +void            g_option_context_set_translate_func (GOptionContext     *context, +						     GTranslateFunc      func, +						     gpointer            data, +						     GDestroyNotify      destroy_notify); +void            g_option_context_set_translation_domain (GOptionContext  *context, +							 const gchar     *domain); + +void            g_option_context_add_group      (GOptionContext *context, +						 GOptionGroup   *group); +void          g_option_context_set_main_group (GOptionContext *context, +					       GOptionGroup   *group); +GOptionGroup *g_option_context_get_main_group (GOptionContext *context); +gchar        *g_option_context_get_help       (GOptionContext *context, +                                               gboolean        main_help, +                                               GOptionGroup   *group); + +GOptionGroup *g_option_group_new                    (const gchar        *name, +						     const gchar        *description, +						     const gchar        *help_description, +						     gpointer            user_data, +						     GDestroyNotify      destroy); +void	      g_option_group_set_parse_hooks	    (GOptionGroup       *group, +						     GOptionParseFunc    pre_parse_func, +						     GOptionParseFunc	 post_parse_func); +void	      g_option_group_set_error_hook	    (GOptionGroup       *group, +						     GOptionErrorFunc	 error_func); +void          g_option_group_free                   (GOptionGroup       *group); +void          g_option_group_add_entries            (GOptionGroup       *group, +						     const GOptionEntry *entries); +void          g_option_group_set_translate_func     (GOptionGroup       *group, +						     GTranslateFunc      func, +						     gpointer            data, +						     GDestroyNotify      destroy_notify); +void          g_option_group_set_translation_domain (GOptionGroup       *group, +						     const gchar        *domain); + +G_END_DECLS + +#endif /* __G_OPTION_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gpattern.h b/protocols/Sametime/src/glib/include/glib/gpattern.h new file mode 100644 index 0000000000..b653d713f0 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gpattern.h @@ -0,0 +1,49 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997, 1999  Peter Mattis, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_PATTERN_H__ +#define __G_PATTERN_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + + +typedef struct _GPatternSpec    GPatternSpec; + +GPatternSpec* g_pattern_spec_new       (const gchar  *pattern); +void          g_pattern_spec_free      (GPatternSpec *pspec); +gboolean      g_pattern_spec_equal     (GPatternSpec *pspec1, +					GPatternSpec *pspec2); +gboolean      g_pattern_match          (GPatternSpec *pspec, +					guint         string_length, +					const gchar  *string, +					const gchar  *string_reversed); +gboolean      g_pattern_match_string   (GPatternSpec *pspec, +					const gchar  *string); +gboolean      g_pattern_match_simple   (const gchar  *pattern, +					const gchar  *string); + +G_END_DECLS + +#endif /* __G_PATTERN_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gpoll.h b/protocols/Sametime/src/glib/include/glib/gpoll.h new file mode 100644 index 0000000000..cc79381a69 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gpoll.h @@ -0,0 +1,117 @@ +/* gpoll.h - poll(2) support + * Copyright (C) 2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if !defined (__GLIB_H_INSIDE__) && !defined (__G_MAIN_H__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_POLL_H__ +#define __G_POLL_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +/* Any definitions using GPollFD or GPollFunc are primarily + * for Unix and not guaranteed to be the compatible on all + * operating systems on which GLib runs. Right now, the + * GLib does use these functions on Win32 as well, but interprets + * them in a fairly different way than on Unix. If you use + * these definitions, you are should be prepared to recode + * for different operating systems. + * + * Note that on systems with a working poll(2), that function is used + * in place of g_poll(). Thus g_poll() must have the same signature as + * poll(), meaning GPollFD must have the same layout as struct pollfd. + * + * + * On Win32, the fd in a GPollFD should be Win32 HANDLE (*not* a file + * descriptor as provided by the C runtime) that can be used by + * MsgWaitForMultipleObjects. This does *not* include file handles + * from CreateFile, SOCKETs, nor pipe handles. (But you can use + * WSAEventSelect to signal events when a SOCKET is readable). + * + * On Win32, fd can also be the special value G_WIN32_MSG_HANDLE to + * indicate polling for messages. + * + * But note that G_WIN32_MSG_HANDLE GPollFDs should not be used by GDK + * (GTK) programs, as GDK itself wants to read messages and convert them + * to GDK events. + * + * So, unless you really know what you are doing, it's best not to try + * to use the main loop polling stuff for your own needs on + * Windows. + */ +typedef struct _GPollFD GPollFD; + +/** + * GPollFunc: + * @ufds: an array of #GPollFD elements + * @nfsd: the number of elements in @ufds + * @timeout_: the maximum time to wait for an event of the file descriptors. + *     A negative value indicates an infinite timeout. + * + * Specifies the type of function passed to g_main_context_set_poll_func(). + * The semantics of the function should match those of the poll() system call. + * + * Returns: the number of #GPollFD elements which have events or errors + *     reported, or -1 if an error occurred. + */ +typedef gint    (*GPollFunc)    (GPollFD *ufds, +                                 guint    nfsd, +                                 gint     timeout_); + +/** + * GPollFD: + * @fd: the file descriptor to poll (or a <type>HANDLE</type> on Win32) + * @events: a bitwise combination from #GIOCondition, specifying which + *     events should be polled for. Typically for reading from a file + *     descriptor you would use %G_IO_IN | %G_IO_HUP | %G_IO_ERR, and + *     for writing you would use %G_IO_OUT | %G_IO_ERR. + * @revents: a bitwise combination of flags from #GIOCondition, returned + *     from the poll() function to indicate which events occurred. + */ +struct _GPollFD +{ +#if defined (G_OS_WIN32) && GLIB_SIZEOF_VOID_P == 8 +  gint64	fd; +#else +  gint		fd; +#endif +  gushort 	events; +  gushort 	revents; +}; + +#ifdef G_OS_WIN32 +#if GLIB_SIZEOF_VOID_P == 8 +#define G_POLLFD_FORMAT "%#I64x" +#else +#define G_POLLFD_FORMAT "%#x" +#endif +#else +#define G_POLLFD_FORMAT "%d" +#endif + +gint g_poll (GPollFD *fds, +	     guint    nfds, +	     gint     timeout); + +G_END_DECLS + +#endif /* __G_POLL_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gprimes.h b/protocols/Sametime/src/glib/include/glib/gprimes.h new file mode 100644 index 0000000000..af5728602b --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gprimes.h @@ -0,0 +1,51 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_PRIMES_H__ +#define __G_PRIMES_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +/* Prime numbers. + */ + +/* This function returns prime numbers spaced by approximately 1.5-2.0 + * and is for use in resizing data structures which prefer + * prime-valued sizes.	The closest spaced prime function returns the + * next largest prime, or the highest it knows about which is about + * MAXINT/4. + */ +guint	   g_spaced_primes_closest (guint num) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __G_PRIMES_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gqsort.h b/protocols/Sametime/src/glib/include/glib/gqsort.h new file mode 100644 index 0000000000..3a47a584ee --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gqsort.h @@ -0,0 +1,46 @@ + /* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_QSORT_H__ +#define __G_QSORT_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +void g_qsort_with_data (gconstpointer    pbase, +			gint             total_elems, +			gsize            size, +			GCompareDataFunc compare_func, +			gpointer         user_data); + +G_END_DECLS + +#endif /* __G_QSORT_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gquark.h b/protocols/Sametime/src/glib/include/glib/gquark.h new file mode 100644 index 0000000000..a0cbe2fd72 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gquark.h @@ -0,0 +1,52 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_QUARK_H__ +#define __G_QUARK_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +typedef guint32 GQuark; + +/* Quarks (string<->id association) + */ +GQuark                g_quark_try_string         (const gchar *string); +GQuark                g_quark_from_static_string (const gchar *string); +GQuark                g_quark_from_string        (const gchar *string); +G_CONST_RETURN gchar* g_quark_to_string          (GQuark       quark) G_GNUC_CONST; + +G_CONST_RETURN gchar* g_intern_string            (const gchar *string); +G_CONST_RETURN gchar* g_intern_static_string     (const gchar *string); + +G_END_DECLS + +#endif /* __G_QUARK_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gqueue.h b/protocols/Sametime/src/glib/include/glib/gqueue.h new file mode 100644 index 0000000000..e78488fb65 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gqueue.h @@ -0,0 +1,127 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_QUEUE_H__ +#define __G_QUEUE_H__ + +#include <glib/glist.h> + +G_BEGIN_DECLS + +typedef struct _GQueue		GQueue; + +struct _GQueue +{ +  GList *head; +  GList *tail; +  guint  length; +}; + +#define G_QUEUE_INIT { NULL, NULL, 0 } + +/* Queues + */ +GQueue*  g_queue_new            (void); +void     g_queue_free           (GQueue           *queue); +void     g_queue_init           (GQueue           *queue); +void     g_queue_clear          (GQueue           *queue); +gboolean g_queue_is_empty       (GQueue           *queue); +guint    g_queue_get_length     (GQueue           *queue); +void     g_queue_reverse        (GQueue           *queue); +GQueue * g_queue_copy           (GQueue           *queue); +void     g_queue_foreach        (GQueue           *queue, +				 GFunc             func, +				 gpointer          user_data); +GList *  g_queue_find           (GQueue           *queue, +				 gconstpointer     data); +GList *  g_queue_find_custom    (GQueue           *queue, +				 gconstpointer     data, +				 GCompareFunc      func); +void     g_queue_sort           (GQueue           *queue, +				 GCompareDataFunc  compare_func, +				 gpointer          user_data); + +void     g_queue_push_head      (GQueue           *queue, +				 gpointer          data); +void     g_queue_push_tail      (GQueue           *queue, +				 gpointer          data); +void     g_queue_push_nth       (GQueue           *queue, +				 gpointer          data, +				 gint              n); +gpointer g_queue_pop_head       (GQueue           *queue); +gpointer g_queue_pop_tail       (GQueue           *queue); +gpointer g_queue_pop_nth        (GQueue           *queue, +				 guint             n); +gpointer g_queue_peek_head      (GQueue           *queue); +gpointer g_queue_peek_tail      (GQueue           *queue); +gpointer g_queue_peek_nth       (GQueue           *queue, +				 guint             n); +gint     g_queue_index          (GQueue           *queue, +				 gconstpointer     data); +void     g_queue_remove         (GQueue           *queue, +				 gconstpointer     data); +void     g_queue_remove_all     (GQueue           *queue, +				 gconstpointer     data); +void     g_queue_insert_before  (GQueue           *queue, +				 GList            *sibling, +				 gpointer          data); +void     g_queue_insert_after   (GQueue           *queue, +				 GList            *sibling, +				 gpointer          data); +void     g_queue_insert_sorted  (GQueue           *queue, +				 gpointer          data, +				 GCompareDataFunc  func, +				 gpointer          user_data); + +void     g_queue_push_head_link (GQueue           *queue, +				 GList            *link_); +void     g_queue_push_tail_link (GQueue           *queue, +				 GList            *link_); +void     g_queue_push_nth_link  (GQueue           *queue, +				 gint              n, +				 GList            *link_); +GList*   g_queue_pop_head_link  (GQueue           *queue); +GList*   g_queue_pop_tail_link  (GQueue           *queue); +GList*   g_queue_pop_nth_link   (GQueue           *queue, +				 guint             n); +GList*   g_queue_peek_head_link (GQueue           *queue); +GList*   g_queue_peek_tail_link (GQueue           *queue); +GList*   g_queue_peek_nth_link  (GQueue           *queue, +				 guint             n); +gint     g_queue_link_index     (GQueue           *queue, +				 GList            *link_); +void     g_queue_unlink         (GQueue           *queue, +				 GList            *link_); +void     g_queue_delete_link    (GQueue           *queue, +				 GList            *link_); + +G_END_DECLS + +#endif /* __G_QUEUE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/grand.h b/protocols/Sametime/src/glib/include/glib/grand.h new file mode 100644 index 0000000000..07907dfc17 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/grand.h @@ -0,0 +1,85 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_RAND_H__ +#define __G_RAND_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +typedef struct _GRand           GRand; + +/* GRand - a good and fast random number generator: Mersenne Twister + * see http://www.math.keio.ac.jp/~matumoto/emt.html for more info. + * The range functions return a value in the intervall [begin, end). + * int          -> [0..2^32-1] + * int_range    -> [begin..end-1] + * double       -> [0..1) + * double_range -> [begin..end) + */ + +GRand*  g_rand_new_with_seed  (guint32  seed); +GRand*  g_rand_new_with_seed_array (const guint32 *seed, +				    guint seed_length); +GRand*  g_rand_new            (void); +void    g_rand_free           (GRand   *rand_); +GRand*  g_rand_copy           (GRand   *rand_); +void    g_rand_set_seed       (GRand   *rand_, +			       guint32  seed); +void	g_rand_set_seed_array (GRand   *rand_, +			       const guint32 *seed, +			       guint    seed_length); + +#define g_rand_boolean(rand_) ((g_rand_int (rand_) & (1 << 15)) != 0) + +guint32 g_rand_int            (GRand   *rand_); +gint32  g_rand_int_range      (GRand   *rand_, +			       gint32   begin, +			       gint32   end); +gdouble g_rand_double         (GRand   *rand_); +gdouble g_rand_double_range   (GRand   *rand_, +			       gdouble  begin, +			       gdouble  end); +void    g_random_set_seed     (guint32  seed); + +#define g_random_boolean() ((g_random_int () & (1 << 15)) != 0) + +guint32 g_random_int          (void); +gint32  g_random_int_range    (gint32   begin, +			       gint32   end); +gdouble g_random_double       (void); +gdouble g_random_double_range (gdouble  begin, +			       gdouble  end); + + +G_END_DECLS + +#endif /* __G_RAND_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gregex.h b/protocols/Sametime/src/glib/include/glib/gregex.h new file mode 100644 index 0000000000..ce1b44a972 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gregex.h @@ -0,0 +1,471 @@ +/* GRegex -- regular expression API wrapper around PCRE. + * + * Copyright (C) 1999, 2000 Scott Wimer + * Copyright (C) 2004, Matthias Clasen <mclasen@redhat.com> + * Copyright (C) 2005 - 2007, Marco Barisione <marco@barisione.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_REGEX_H__ +#define __G_REGEX_H__ + +#include <glib/gerror.h> +#include <glib/gstring.h> + +G_BEGIN_DECLS + +/** + * GRegexError: + * @G_REGEX_ERROR_COMPILE: Compilation of the regular expression failed. + * @G_REGEX_ERROR_OPTIMIZE: Optimization of the regular expression failed. + * @G_REGEX_ERROR_REPLACE: Replacement failed due to an ill-formed replacement + *     string. + * @G_REGEX_ERROR_MATCH: The match process failed. + * @G_REGEX_ERROR_INTERNAL: Internal error of the regular expression engine. + *     Since 2.16 + * @G_REGEX_ERROR_STRAY_BACKSLASH: "\\" at end of pattern. Since 2.16 + * @G_REGEX_ERROR_MISSING_CONTROL_CHAR: "\\c" at end of pattern. Since 2.16 + * @G_REGEX_ERROR_UNRECOGNIZED_ESCAPE: Unrecognized character follows "\\". + *     Since 2.16 + * @G_REGEX_ERROR_QUANTIFIERS_OUT_OF_ORDER: Numbers out of order in "{}" + *     quantifier. Since 2.16 + * @G_REGEX_ERROR_QUANTIFIER_TOO_BIG: Number too big in "{}" quantifier. + *     Since 2.16 + * @G_REGEX_ERROR_UNTERMINATED_CHARACTER_CLASS: Missing terminating "]" for + *     character class. Since 2.16 + * @G_REGEX_ERROR_INVALID_ESCAPE_IN_CHARACTER_CLASS: Invalid escape sequence + *     in character class. Since 2.16 + * @G_REGEX_ERROR_RANGE_OUT_OF_ORDER: Range out of order in character class. + *     Since 2.16 + * @G_REGEX_ERROR_NOTHING_TO_REPEAT: Nothing to repeat. Since 2.16 + * @G_REGEX_ERROR_UNRECOGNIZED_CHARACTER: Unrecognized character after "(?", + *     "(?<" or "(?P". Since 2.16 + * @G_REGEX_ERROR_POSIX_NAMED_CLASS_OUTSIDE_CLASS: POSIX named classes are + *     supported only within a class. Since 2.16 + * @G_REGEX_ERROR_UNMATCHED_PARENTHESIS: Missing terminating ")" or ")" + *     without opening "(". Since 2.16 + * @G_REGEX_ERROR_INEXISTENT_SUBPATTERN_REFERENCE: Reference to non-existent + *     subpattern. Since 2.16 + * @G_REGEX_ERROR_UNTERMINATED_COMMENT: Missing terminating ")" after comment. + *     Since 2.16 + * @G_REGEX_ERROR_EXPRESSION_TOO_LARGE: Regular expression too large. + *     Since 2.16 + * @G_REGEX_ERROR_MEMORY_ERROR: Failed to get memory. Since 2.16 + * @G_REGEX_ERROR_VARIABLE_LENGTH_LOOKBEHIND: Lookbehind assertion is not + *     fixed length. Since 2.16 + * @G_REGEX_ERROR_MALFORMED_CONDITION: Malformed number or name after "(?(". + *     Since 2.16 + * @G_REGEX_ERROR_TOO_MANY_CONDITIONAL_BRANCHES: Conditional group contains + *     more than two branches. Since 2.16 + * @G_REGEX_ERROR_ASSERTION_EXPECTED: Assertion expected after "(?(". + *     Since 2.16 + * @G_REGEX_ERROR_UNKNOWN_POSIX_CLASS_NAME: Unknown POSIX class name. + *     Since 2.16 + * @G_REGEX_ERROR_POSIX_COLLATING_ELEMENTS_NOT_SUPPORTED: POSIX collating + *     elements are not supported. Since 2.16 + * @G_REGEX_ERROR_HEX_CODE_TOO_LARGE: Character value in "\\x{...}" sequence + *     is too large. Since 2.16 + * @G_REGEX_ERROR_INVALID_CONDITION: Invalid condition "(?(0)". Since 2.16 + * @G_REGEX_ERROR_SINGLE_BYTE_MATCH_IN_LOOKBEHIND: \\C not allowed in + *     lookbehind assertion. Since 2.16 + * @G_REGEX_ERROR_INFINITE_LOOP: Recursive call could loop indefinitely. + *     Since 2.16 + * @G_REGEX_ERROR_MISSING_SUBPATTERN_NAME_TERMINATOR: Missing terminator + *     in subpattern name. Since 2.16 + * @G_REGEX_ERROR_DUPLICATE_SUBPATTERN_NAME: Two named subpatterns have + *     the same name. Since 2.16 + * @G_REGEX_ERROR_MALFORMED_PROPERTY: Malformed "\\P" or "\\p" sequence. + *     Since 2.16 + * @G_REGEX_ERROR_UNKNOWN_PROPERTY: Unknown property name after "\\P" or + *     "\\p". Since 2.16 + * @G_REGEX_ERROR_SUBPATTERN_NAME_TOO_LONG: Subpattern name is too long + *     (maximum 32 characters). Since 2.16 + * @G_REGEX_ERROR_TOO_MANY_SUBPATTERNS: Too many named subpatterns (maximum + *     10,000). Since 2.16 + * @G_REGEX_ERROR_INVALID_OCTAL_VALUE: Octal value is greater than "\\377". + *     Since 2.16 + * @G_REGEX_ERROR_TOO_MANY_BRANCHES_IN_DEFINE: "DEFINE" group contains more + *     than one branch. Since 2.16 + * @G_REGEX_ERROR_DEFINE_REPETION: Repeating a "DEFINE" group is not allowed. + *     Since 2.16 + * @G_REGEX_ERROR_INCONSISTENT_NEWLINE_OPTIONS: Inconsistent newline options. + *     Since 2.16 + * @G_REGEX_ERROR_MISSING_BACK_REFERENCE: "\\g" is not followed by a braced + *     name or an optionally braced non-zero number. Since 2.16 + * + * Error codes returned by regular expressions functions. + * + * Since: 2.14 + */ +typedef enum +{ +  G_REGEX_ERROR_COMPILE, +  G_REGEX_ERROR_OPTIMIZE, +  G_REGEX_ERROR_REPLACE, +  G_REGEX_ERROR_MATCH, +  G_REGEX_ERROR_INTERNAL, + +  /* These are the error codes from PCRE + 100 */ +  G_REGEX_ERROR_STRAY_BACKSLASH = 101, +  G_REGEX_ERROR_MISSING_CONTROL_CHAR = 102, +  G_REGEX_ERROR_UNRECOGNIZED_ESCAPE = 103, +  G_REGEX_ERROR_QUANTIFIERS_OUT_OF_ORDER = 104, +  G_REGEX_ERROR_QUANTIFIER_TOO_BIG = 105, +  G_REGEX_ERROR_UNTERMINATED_CHARACTER_CLASS = 106, +  G_REGEX_ERROR_INVALID_ESCAPE_IN_CHARACTER_CLASS = 107, +  G_REGEX_ERROR_RANGE_OUT_OF_ORDER = 108, +  G_REGEX_ERROR_NOTHING_TO_REPEAT = 109, +  G_REGEX_ERROR_UNRECOGNIZED_CHARACTER = 112, +  G_REGEX_ERROR_POSIX_NAMED_CLASS_OUTSIDE_CLASS = 113, +  G_REGEX_ERROR_UNMATCHED_PARENTHESIS = 114, +  G_REGEX_ERROR_INEXISTENT_SUBPATTERN_REFERENCE = 115, +  G_REGEX_ERROR_UNTERMINATED_COMMENT = 118, +  G_REGEX_ERROR_EXPRESSION_TOO_LARGE = 120, +  G_REGEX_ERROR_MEMORY_ERROR = 121, +  G_REGEX_ERROR_VARIABLE_LENGTH_LOOKBEHIND = 125, +  G_REGEX_ERROR_MALFORMED_CONDITION = 126, +  G_REGEX_ERROR_TOO_MANY_CONDITIONAL_BRANCHES = 127, +  G_REGEX_ERROR_ASSERTION_EXPECTED = 128, +  G_REGEX_ERROR_UNKNOWN_POSIX_CLASS_NAME = 130, +  G_REGEX_ERROR_POSIX_COLLATING_ELEMENTS_NOT_SUPPORTED = 131, +  G_REGEX_ERROR_HEX_CODE_TOO_LARGE = 134, +  G_REGEX_ERROR_INVALID_CONDITION = 135, +  G_REGEX_ERROR_SINGLE_BYTE_MATCH_IN_LOOKBEHIND = 136, +  G_REGEX_ERROR_INFINITE_LOOP = 140, +  G_REGEX_ERROR_MISSING_SUBPATTERN_NAME_TERMINATOR = 142, +  G_REGEX_ERROR_DUPLICATE_SUBPATTERN_NAME = 143, +  G_REGEX_ERROR_MALFORMED_PROPERTY = 146, +  G_REGEX_ERROR_UNKNOWN_PROPERTY = 147, +  G_REGEX_ERROR_SUBPATTERN_NAME_TOO_LONG = 148, +  G_REGEX_ERROR_TOO_MANY_SUBPATTERNS = 149, +  G_REGEX_ERROR_INVALID_OCTAL_VALUE = 151, +  G_REGEX_ERROR_TOO_MANY_BRANCHES_IN_DEFINE = 154, +  G_REGEX_ERROR_DEFINE_REPETION = 155, +  G_REGEX_ERROR_INCONSISTENT_NEWLINE_OPTIONS = 156, +  G_REGEX_ERROR_MISSING_BACK_REFERENCE = 157 +} GRegexError; + +/** + * G_REGEX_ERROR: + * + * Error domain for regular expressions. Errors in this domain will be + * from the #GRegexError enumeration. See #GError for information on + * error domains. + * + * Since: 2.14 + */ +#define G_REGEX_ERROR g_regex_error_quark () + +GQuark g_regex_error_quark (void); + +/** + * GRegexCompileFlags: + * @G_REGEX_CASELESS: Letters in the pattern match both upper- and + *     lowercase letters. This option can be changed within a pattern + *     by a "(?i)" option setting. + * @G_REGEX_MULTILINE: By default, GRegex treats the strings as consisting + *     of a single line of characters (even if it actually contains + *     newlines). The "start of line" metacharacter ("^") matches only + *     at the start of the string, while the "end of line" metacharacter + *     ("$") matches only at the end of the string, or before a terminating + *     newline (unless #G_REGEX_DOLLAR_ENDONLY is set). When + *     #G_REGEX_MULTILINE is set, the "start of line" and "end of line" + *     constructs match immediately following or immediately before any + *     newline in the string, respectively, as well as at the very start + *     and end. This can be changed within a pattern by a "(?m)" option + *     setting. + * @G_REGEX_DOTALL: A dot metacharater (".") in the pattern matches all + *     characters, including newlines. Without it, newlines are excluded. + *     This option can be changed within a pattern by a ("?s") option setting. + * @G_REGEX_EXTENDED: Whitespace data characters in the pattern are + *     totally ignored except when escaped or inside a character class. + *     Whitespace does not include the VT character (code 11). In addition, + *     characters between an unescaped "#" outside a character class and + *     the next newline character, inclusive, are also ignored. This can + *     be changed within a pattern by a "(?x)" option setting. + * @G_REGEX_ANCHORED: The pattern is forced to be "anchored", that is, + *     it is constrained to match only at the first matching point in the + *     string that is being searched. This effect can also be achieved by + *     appropriate constructs in the pattern itself such as the "^" + *     metacharater. + * @G_REGEX_DOLLAR_ENDONLY: A dollar metacharacter ("$") in the pattern + *     matches only at the end of the string. Without this option, a + *     dollar also matches immediately before the final character if + *     it is a newline (but not before any other newlines). This option + *     is ignored if #G_REGEX_MULTILINE is set. + * @G_REGEX_UNGREEDY: Inverts the "greediness" of the quantifiers so that + *     they are not greedy by default, but become greedy if followed by "?". + *     It can also be set by a "(?U)" option setting within the pattern. + * @G_REGEX_RAW: Usually strings must be valid UTF-8 strings, using this + *     flag they are considered as a raw sequence of bytes. + *     @G_REGEX_NO_AUTO_CAPTURE: Disables the use of numbered capturing + *     parentheses in the pattern. Any opening parenthesis that is not + *     followed by "?" behaves as if it were followed by "?:" but named + *     parentheses can still be used for capturing (and they acquire numbers + *     in the usual way). + * @G_REGEX_OPTIMIZE: Optimize the regular expression. If the pattern will + *     be used many times, then it may be worth the effort to optimize it + *     to improve the speed of matches. + * @G_REGEX_DUPNAMES: Names used to identify capturing subpatterns need not + *     be unique. This can be helpful for certain types of pattern when it + *     is known that only one instance of the named subpattern can ever be + *     matched. + * @G_REGEX_NEWLINE_CR: Usually any newline character is recognized, if this + *     option is set, the only recognized newline character is '\r'. + * @G_REGEX_NEWLINE_LF: Usually any newline character is recognized, if this + *     option is set, the only recognized newline character is '\n'. + * @G_REGEX_NEWLINE_CRLF: Usually any newline character is recognized, if this + *     option is set, the only recognized newline character sequence is '\r\n'. + * + * Flags specifying compile-time options. + * + * Since: 2.14 + */ +/* Remember to update G_REGEX_COMPILE_MASK in gregex.c after + * adding a new flag. */ +typedef enum +{ +  G_REGEX_CASELESS          = 1 << 0, +  G_REGEX_MULTILINE         = 1 << 1, +  G_REGEX_DOTALL            = 1 << 2, +  G_REGEX_EXTENDED          = 1 << 3, +  G_REGEX_ANCHORED          = 1 << 4, +  G_REGEX_DOLLAR_ENDONLY    = 1 << 5, +  G_REGEX_UNGREEDY          = 1 << 9, +  G_REGEX_RAW               = 1 << 11, +  G_REGEX_NO_AUTO_CAPTURE   = 1 << 12, +  G_REGEX_OPTIMIZE          = 1 << 13, +  G_REGEX_DUPNAMES          = 1 << 19, +  G_REGEX_NEWLINE_CR        = 1 << 20, +  G_REGEX_NEWLINE_LF        = 1 << 21, +  G_REGEX_NEWLINE_CRLF      = G_REGEX_NEWLINE_CR | G_REGEX_NEWLINE_LF +} GRegexCompileFlags; + +/** + * GRegexMatchFlags: + * @G_REGEX_MATCH_ANCHORED: The pattern is forced to be "anchored", that is, + *     it is constrained to match only at the first matching point in the + *     string that is being searched. This effect can also be achieved by + *     appropriate constructs in the pattern itself such as the "^" + *     metacharater. + * @G_REGEX_MATCH_NOTBOL: Specifies that first character of the string is + *     not the beginning of a line, so the circumflex metacharacter should + *     not match before it. Setting this without #G_REGEX_MULTILINE (at + *     compile time) causes circumflex never to match. This option affects + *     only the behaviour of the circumflex metacharacter, it does not + *     affect "\A". + * @G_REGEX_MATCH_NOTEOL: Specifies that the end of the subject string is + *     not the end of a line, so the dollar metacharacter should not match + *     it nor (except in multiline mode) a newline immediately before it. + *     Setting this without #G_REGEX_MULTILINE (at compile time) causes + *     dollar never to match. This option affects only the behaviour of + *     the dollar metacharacter, it does not affect "\Z" or "\z". + * @G_REGEX_MATCH_NOTEMPTY: An empty string is not considered to be a valid + *     match if this option is set. If there are alternatives in the pattern, + *     they are tried. If all the alternatives match the empty string, the + *     entire match fails. For example, if the pattern "a?b?" is applied to + *     a string not beginning with "a" or "b", it matches the empty string + *     at the start of the string. With this flag set, this match is not + *     valid, so GRegex searches further into the string for occurrences + *     of "a" or "b". + * @G_REGEX_MATCH_PARTIAL: Turns on the partial matching feature, for more + *     documentation on partial matching see g_match_info_is_partial_match(). + * @G_REGEX_MATCH_NEWLINE_CR: Overrides the newline definition set when + *     creating a new #GRegex, setting the '\r' character as line terminator. + * @G_REGEX_MATCH_NEWLINE_LF: Overrides the newline definition set when + *     creating a new #GRegex, setting the '\n' character as line terminator. + * @G_REGEX_MATCH_NEWLINE_CRLF: Overrides the newline definition set when + *     creating a new #GRegex, setting the '\r\n' characters as line terminator. + * @G_REGEX_MATCH_NEWLINE_ANY: Overrides the newline definition set when + *     creating a new #GRegex, any newline character or character sequence + *     is recognized. + * + * Flags specifying match-time options. + * + * Since: 2.14 + */ +/* Remember to update G_REGEX_MATCH_MASK in gregex.c after + * adding a new flag. */ +typedef enum +{ +  G_REGEX_MATCH_ANCHORED      = 1 << 4, +  G_REGEX_MATCH_NOTBOL        = 1 << 7, +  G_REGEX_MATCH_NOTEOL        = 1 << 8, +  G_REGEX_MATCH_NOTEMPTY      = 1 << 10, +  G_REGEX_MATCH_PARTIAL       = 1 << 15, +  G_REGEX_MATCH_NEWLINE_CR    = 1 << 20, +  G_REGEX_MATCH_NEWLINE_LF    = 1 << 21, +  G_REGEX_MATCH_NEWLINE_CRLF  = G_REGEX_MATCH_NEWLINE_CR | G_REGEX_MATCH_NEWLINE_LF, +  G_REGEX_MATCH_NEWLINE_ANY   = 1 << 22 +} GRegexMatchFlags; + +/** + * GRegex: + * + * A GRegex is the "compiled" form of a regular expression pattern. This + * structure is opaque and its fields cannot be accessed directly. + * + * Since: 2.14 + */ +typedef struct _GRegex		GRegex; + + +typedef struct _GMatchInfo	GMatchInfo; + +/** + * GRegexEvalCallback: + * @match_info: the #GMatchInfo generated by the match. + *     Use g_match_info_get_regex() and g_match_info_get_string() if you + *     need the #GRegex or the matched string. + * @result: a #GString containing the new string + * @user_data: user data passed to g_regex_replace_eval() + * + * Specifies the type of the function passed to g_regex_replace_eval(). + * It is called for each occurance of the pattern in the string passed + * to g_regex_replace_eval(), and it should append the replacement to + * @result. + * + * Returns: %FALSE to continue the replacement process, %TRUE to stop it + * + * Since: 2.14 + */ +typedef gboolean (*GRegexEvalCallback)		(const GMatchInfo *match_info, +						 GString          *result, +						 gpointer          user_data); + + +GRegex		 *g_regex_new			(const gchar         *pattern, +						 GRegexCompileFlags   compile_options, +						 GRegexMatchFlags     match_options, +						 GError             **error); +GRegex           *g_regex_ref			(GRegex              *regex); +void		  g_regex_unref			(GRegex              *regex); +const gchar	 *g_regex_get_pattern		(const GRegex        *regex); +gint		  g_regex_get_max_backref	(const GRegex        *regex); +gint		  g_regex_get_capture_count	(const GRegex        *regex); +gint		  g_regex_get_string_number	(const GRegex        *regex,  +						 const gchar         *name); +gchar		 *g_regex_escape_string		(const gchar         *string, +						 gint                 length); + +GRegexCompileFlags g_regex_get_compile_flags    (const GRegex        *regex); +GRegexMatchFlags   g_regex_get_match_flags      (const GRegex        *regex); + +/* Matching. */ +gboolean	  g_regex_match_simple		(const gchar         *pattern, +						 const gchar         *string, +						 GRegexCompileFlags   compile_options, +						 GRegexMatchFlags     match_options); +gboolean	  g_regex_match			(const GRegex        *regex, +						 const gchar         *string, +						 GRegexMatchFlags     match_options, +						 GMatchInfo         **match_info); +gboolean	  g_regex_match_full		(const GRegex        *regex, +						 const gchar         *string, +						 gssize               string_len, +						 gint                 start_position, +						 GRegexMatchFlags     match_options, +						 GMatchInfo         **match_info, +						 GError             **error); +gboolean	  g_regex_match_all		(const GRegex        *regex, +						 const gchar         *string, +						 GRegexMatchFlags     match_options, +						 GMatchInfo         **match_info); +gboolean	  g_regex_match_all_full	(const GRegex        *regex, +						 const gchar         *string, +						 gssize               string_len, +						 gint                 start_position, +						 GRegexMatchFlags     match_options, +						 GMatchInfo         **match_info, +						 GError             **error); + +/* String splitting. */ +gchar		**g_regex_split_simple		(const gchar         *pattern, +						 const gchar         *string, +						 GRegexCompileFlags   compile_options, +						 GRegexMatchFlags     match_options); +gchar		**g_regex_split			(const GRegex        *regex, +						 const gchar         *string, +						 GRegexMatchFlags     match_options); +gchar		**g_regex_split_full		(const GRegex        *regex, +						 const gchar         *string, +						 gssize               string_len, +						 gint                 start_position, +						 GRegexMatchFlags     match_options, +						 gint                 max_tokens, +						 GError             **error); + +/* String replacement. */ +gchar		 *g_regex_replace		(const GRegex        *regex, +						 const gchar         *string, +						 gssize               string_len, +						 gint                 start_position, +						 const gchar         *replacement, +						 GRegexMatchFlags     match_options, +						 GError             **error); +gchar		 *g_regex_replace_literal	(const GRegex        *regex, +						 const gchar         *string, +						 gssize               string_len, +						 gint                 start_position, +						 const gchar         *replacement, +						 GRegexMatchFlags     match_options, +						 GError             **error); +gchar		 *g_regex_replace_eval		(const GRegex        *regex, +						 const gchar         *string, +						 gssize               string_len, +						 gint                 start_position, +						 GRegexMatchFlags     match_options, +						 GRegexEvalCallback   eval, +						 gpointer             user_data, +						 GError             **error); +gboolean	  g_regex_check_replacement	(const gchar         *replacement, +						 gboolean            *has_references, +						 GError             **error); + +/* Match info */ +GRegex		 *g_match_info_get_regex	(const GMatchInfo    *match_info); +const gchar      *g_match_info_get_string       (const GMatchInfo    *match_info); + +void		  g_match_info_free		(GMatchInfo          *match_info); +gboolean	  g_match_info_next		(GMatchInfo          *match_info, +						 GError             **error); +gboolean	  g_match_info_matches		(const GMatchInfo    *match_info); +gint		  g_match_info_get_match_count	(const GMatchInfo    *match_info); +gboolean	  g_match_info_is_partial_match	(const GMatchInfo    *match_info); +gchar		 *g_match_info_expand_references(const GMatchInfo    *match_info, +						 const gchar         *string_to_expand, +						 GError             **error); +gchar		 *g_match_info_fetch		(const GMatchInfo    *match_info, +						 gint                 match_num); +gboolean	  g_match_info_fetch_pos	(const GMatchInfo    *match_info, +						 gint                 match_num, +						 gint                *start_pos, +						 gint                *end_pos); +gchar		 *g_match_info_fetch_named	(const GMatchInfo    *match_info, +						 const gchar         *name); +gboolean	  g_match_info_fetch_named_pos	(const GMatchInfo    *match_info, +						 const gchar         *name, +						 gint                *start_pos, +						 gint                *end_pos); +gchar		**g_match_info_fetch_all	(const GMatchInfo    *match_info); + +G_END_DECLS + +#endif  /*  __G_REGEX_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/grel.h b/protocols/Sametime/src/glib/include/glib/grel.h new file mode 100644 index 0000000000..5cb8d09d4b --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/grel.h @@ -0,0 +1,101 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_REL_H__ +#define __G_REL_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +typedef struct _GRelation       GRelation; +typedef struct _GTuples         GTuples; + +struct _GTuples +{ +  guint len; +}; + +/* GRelation + * + * Indexed Relations.  Imagine a really simple table in a + * database.  Relations are not ordered.  This data type is meant for + * maintaining a N-way mapping. + * + * g_relation_new() creates a relation with FIELDS fields + * + * g_relation_destroy() frees all resources + * g_tuples_destroy() frees the result of g_relation_select() + * + * g_relation_index() indexes relation FIELD with the provided + *   equality and hash functions.  this must be done before any + *   calls to insert are made. + * + * g_relation_insert() inserts a new tuple.  you are expected to + *   provide the right number of fields. + * + * g_relation_delete() deletes all relations with KEY in FIELD + * g_relation_select() returns ... + * g_relation_count() counts ... + */ + +#ifndef G_DISABLE_DEPRECATED + +GRelation* g_relation_new     (gint         fields); +void       g_relation_destroy (GRelation   *relation); +void       g_relation_index   (GRelation   *relation, +                               gint         field, +                               GHashFunc    hash_func, +                               GEqualFunc   key_equal_func); +void       g_relation_insert  (GRelation   *relation, +                               ...); +gint       g_relation_delete  (GRelation   *relation, +                               gconstpointer  key, +                               gint         field); +GTuples*   g_relation_select  (GRelation   *relation, +                               gconstpointer  key, +                               gint         field); +gint       g_relation_count   (GRelation   *relation, +                               gconstpointer  key, +                               gint         field); +gboolean   g_relation_exists  (GRelation   *relation, +                               ...); +void       g_relation_print   (GRelation   *relation); + +void       g_tuples_destroy   (GTuples     *tuples); +gpointer   g_tuples_index     (GTuples     *tuples, +                               gint         index_, +                               gint         field); + +#endif + +G_END_DECLS + +#endif /* __G_REL_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gscanner.h b/protocols/Sametime/src/glib/include/glib/gscanner.h new file mode 100644 index 0000000000..3b7ad6fab0 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gscanner.h @@ -0,0 +1,278 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_SCANNER_H__ +#define __G_SCANNER_H__ + +#include <glib/gdataset.h> +#include <glib/ghash.h> + +G_BEGIN_DECLS + +typedef struct _GScanner	GScanner; +typedef struct _GScannerConfig	GScannerConfig; +typedef union  _GTokenValue     GTokenValue; + +typedef void		(*GScannerMsgFunc)	(GScanner      *scanner, +						 gchar	       *message, +						 gboolean	error); + +/* GScanner: Flexible lexical scanner for general purpose. + */ + +/* Character sets */ +#define G_CSET_A_2_Z	"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define G_CSET_a_2_z	"abcdefghijklmnopqrstuvwxyz" +#define G_CSET_DIGITS	"0123456789" +#define G_CSET_LATINC	"\300\301\302\303\304\305\306"\ +			"\307\310\311\312\313\314\315\316\317\320"\ +			"\321\322\323\324\325\326"\ +			"\330\331\332\333\334\335\336" +#define G_CSET_LATINS	"\337\340\341\342\343\344\345\346"\ +			"\347\350\351\352\353\354\355\356\357\360"\ +			"\361\362\363\364\365\366"\ +			"\370\371\372\373\374\375\376\377" + +/* Error types */ +typedef enum +{ +  G_ERR_UNKNOWN, +  G_ERR_UNEXP_EOF, +  G_ERR_UNEXP_EOF_IN_STRING, +  G_ERR_UNEXP_EOF_IN_COMMENT, +  G_ERR_NON_DIGIT_IN_CONST, +  G_ERR_DIGIT_RADIX, +  G_ERR_FLOAT_RADIX, +  G_ERR_FLOAT_MALFORMED +} GErrorType; + +/* Token types */ +typedef enum +{ +  G_TOKEN_EOF			=   0, +   +  G_TOKEN_LEFT_PAREN		= '(', +  G_TOKEN_RIGHT_PAREN		= ')', +  G_TOKEN_LEFT_CURLY		= '{', +  G_TOKEN_RIGHT_CURLY		= '}', +  G_TOKEN_LEFT_BRACE		= '[', +  G_TOKEN_RIGHT_BRACE		= ']', +  G_TOKEN_EQUAL_SIGN		= '=', +  G_TOKEN_COMMA			= ',', +   +  G_TOKEN_NONE			= 256, +   +  G_TOKEN_ERROR, +   +  G_TOKEN_CHAR, +  G_TOKEN_BINARY, +  G_TOKEN_OCTAL, +  G_TOKEN_INT, +  G_TOKEN_HEX, +  G_TOKEN_FLOAT, +  G_TOKEN_STRING, +   +  G_TOKEN_SYMBOL, +  G_TOKEN_IDENTIFIER, +  G_TOKEN_IDENTIFIER_NULL, +   +  G_TOKEN_COMMENT_SINGLE, +  G_TOKEN_COMMENT_MULTI, +  G_TOKEN_LAST +} GTokenType; + +union	_GTokenValue +{ +  gpointer	v_symbol; +  gchar		*v_identifier; +  gulong	v_binary; +  gulong	v_octal; +  gulong	v_int; +  guint64       v_int64; +  gdouble	v_float; +  gulong	v_hex; +  gchar		*v_string; +  gchar		*v_comment; +  guchar	v_char; +  guint		v_error; +}; + +struct	_GScannerConfig +{ +  /* Character sets +   */ +  gchar		*cset_skip_characters;		/* default: " \t\n" */ +  gchar		*cset_identifier_first; +  gchar		*cset_identifier_nth; +  gchar		*cpair_comment_single;		/* default: "#\n" */ +   +  /* Should symbol lookup work case sensitive? +   */ +  guint		case_sensitive : 1; +   +  /* Boolean values to be adjusted "on the fly" +   * to configure scanning behaviour. +   */ +  guint		skip_comment_multi : 1;		/* C like comment */ +  guint		skip_comment_single : 1;	/* single line comment */ +  guint		scan_comment_multi : 1;		/* scan multi line comments? */ +  guint		scan_identifier : 1; +  guint		scan_identifier_1char : 1; +  guint		scan_identifier_NULL : 1; +  guint		scan_symbols : 1; +  guint		scan_binary : 1; +  guint		scan_octal : 1; +  guint		scan_float : 1; +  guint		scan_hex : 1;			/* `0x0ff0' */ +  guint		scan_hex_dollar : 1;		/* `$0ff0' */ +  guint		scan_string_sq : 1;		/* string: 'anything' */ +  guint		scan_string_dq : 1;		/* string: "\\-escapes!\n" */ +  guint		numbers_2_int : 1;		/* bin, octal, hex => int */ +  guint		int_2_float : 1;		/* int => G_TOKEN_FLOAT? */ +  guint		identifier_2_string : 1; +  guint		char_2_token : 1;		/* return G_TOKEN_CHAR? */ +  guint		symbol_2_token : 1; +  guint		scope_0_fallback : 1;		/* try scope 0 on lookups? */ +  guint		store_int64 : 1; 		/* use value.v_int64 rather than v_int */ +  guint		padding_dummy; +}; + +struct	_GScanner +{ +  /* unused fields */ +  gpointer		user_data; +  guint			max_parse_errors; +   +  /* g_scanner_error() increments this field */ +  guint			parse_errors; +   +  /* name of input stream, featured by the default message handler */ +  const gchar		*input_name; +   +  /* quarked data */ +  GData			*qdata; +   +  /* link into the scanner configuration */ +  GScannerConfig	*config; +   +  /* fields filled in after g_scanner_get_next_token() */ +  GTokenType		token; +  GTokenValue		value; +  guint			line; +  guint			position; +   +  /* fields filled in after g_scanner_peek_next_token() */ +  GTokenType		next_token; +  GTokenValue		next_value; +  guint			next_line; +  guint			next_position; +   +  /* to be considered private */ +  GHashTable		*symbol_table; +  gint			input_fd; +  const gchar		*text; +  const gchar		*text_end; +  gchar			*buffer; +  guint			scope_id; +   +  /* handler function for _warn and _error */ +  GScannerMsgFunc	msg_handler; +}; + +GScanner*	g_scanner_new			(const GScannerConfig *config_templ); +void		g_scanner_destroy		(GScanner	*scanner); +void		g_scanner_input_file		(GScanner	*scanner, +						 gint		input_fd); +void		g_scanner_sync_file_offset	(GScanner	*scanner); +void		g_scanner_input_text		(GScanner	*scanner, +						 const	gchar	*text, +						 guint		text_len); +GTokenType	g_scanner_get_next_token	(GScanner	*scanner); +GTokenType	g_scanner_peek_next_token	(GScanner	*scanner); +GTokenType	g_scanner_cur_token		(GScanner	*scanner); +GTokenValue	g_scanner_cur_value		(GScanner	*scanner); +guint		g_scanner_cur_line		(GScanner	*scanner); +guint		g_scanner_cur_position		(GScanner	*scanner); +gboolean	g_scanner_eof			(GScanner	*scanner); +guint		g_scanner_set_scope		(GScanner	*scanner, +						 guint		 scope_id); +void		g_scanner_scope_add_symbol	(GScanner	*scanner, +						 guint		 scope_id, +						 const gchar	*symbol, +						 gpointer	value); +void		g_scanner_scope_remove_symbol	(GScanner	*scanner, +						 guint		 scope_id, +						 const gchar	*symbol); +gpointer	g_scanner_scope_lookup_symbol	(GScanner	*scanner, +						 guint		 scope_id, +						 const gchar	*symbol); +void		g_scanner_scope_foreach_symbol	(GScanner	*scanner, +						 guint		 scope_id, +						 GHFunc		 func, +						 gpointer	 user_data); +gpointer	g_scanner_lookup_symbol		(GScanner	*scanner, +						 const gchar	*symbol); +void		g_scanner_unexp_token		(GScanner	*scanner, +						 GTokenType	expected_token, +						 const gchar	*identifier_spec, +						 const gchar	*symbol_spec, +						 const gchar	*symbol_name, +						 const gchar	*message, +						 gint		 is_error); +void		g_scanner_error			(GScanner	*scanner, +						 const gchar	*format, +						 ...) G_GNUC_PRINTF (2,3); +void		g_scanner_warn			(GScanner	*scanner, +						 const gchar	*format, +						 ...) G_GNUC_PRINTF (2,3); + +#ifndef G_DISABLE_DEPRECATED + +/* keep downward source compatibility */ +#define		g_scanner_add_symbol( scanner, symbol, value )	G_STMT_START { \ +  g_scanner_scope_add_symbol ((scanner), 0, (symbol), (value)); \ +} G_STMT_END +#define		g_scanner_remove_symbol( scanner, symbol )	G_STMT_START { \ +  g_scanner_scope_remove_symbol ((scanner), 0, (symbol)); \ +} G_STMT_END +#define		g_scanner_foreach_symbol( scanner, func, data )	G_STMT_START { \ +  g_scanner_scope_foreach_symbol ((scanner), 0, (func), (data)); \ +} G_STMT_END + +/* The following two functions are deprecated and will be removed in + * the next major release. They do no good. */ +#define g_scanner_freeze_symbol_table(scanner) ((void)0) +#define g_scanner_thaw_symbol_table(scanner) ((void)0) + +#endif /* G_DISABLE_DEPRECATED */ + +G_END_DECLS + +#endif /* __G_SCANNER_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gsequence.h b/protocols/Sametime/src/glib/include/glib/gsequence.h new file mode 100644 index 0000000000..fa79066e06 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gsequence.h @@ -0,0 +1,128 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 + * Soeren Sandmann (sandmann@daimi.au.dk) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_SEQUENCE_H__ +#define __G_SEQUENCE_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +typedef struct _GSequence      GSequence; +typedef struct _GSequenceNode  GSequenceIter; + +typedef gint (* GSequenceIterCompareFunc) (GSequenceIter *a, +                                           GSequenceIter *b, +                                           gpointer       data); + + +/* GSequence */ +GSequence *    g_sequence_new                (GDestroyNotify            data_destroy); +void           g_sequence_free               (GSequence                *seq); +gint           g_sequence_get_length         (GSequence                *seq); +void           g_sequence_foreach            (GSequence                *seq, +                                              GFunc                     func, +                                              gpointer                  user_data); +void           g_sequence_foreach_range      (GSequenceIter            *begin, +                                              GSequenceIter            *end, +                                              GFunc                     func, +                                              gpointer                  user_data); +void           g_sequence_sort               (GSequence                *seq, +                                              GCompareDataFunc          cmp_func, +                                              gpointer                  cmp_data); +void           g_sequence_sort_iter          (GSequence                *seq, +                                              GSequenceIterCompareFunc  cmp_func, +                                              gpointer                  cmp_data); + + +/* Getting iters */ +GSequenceIter *g_sequence_get_begin_iter     (GSequence                *seq); +GSequenceIter *g_sequence_get_end_iter       (GSequence                *seq); +GSequenceIter *g_sequence_get_iter_at_pos    (GSequence                *seq, +                                              gint                      pos); +GSequenceIter *g_sequence_append             (GSequence                *seq, +                                              gpointer                  data); +GSequenceIter *g_sequence_prepend            (GSequence                *seq, +                                              gpointer                  data); +GSequenceIter *g_sequence_insert_before      (GSequenceIter            *iter, +                                              gpointer                  data); +void           g_sequence_move               (GSequenceIter            *src, +                                              GSequenceIter            *dest); +void           g_sequence_swap               (GSequenceIter            *a, +                                              GSequenceIter            *b); +GSequenceIter *g_sequence_insert_sorted      (GSequence                *seq, +                                              gpointer                  data, +                                              GCompareDataFunc          cmp_func, +                                              gpointer                  cmp_data); +GSequenceIter *g_sequence_insert_sorted_iter (GSequence                *seq, +                                              gpointer                  data, +                                              GSequenceIterCompareFunc  iter_cmp, +                                              gpointer                  cmp_data); +void           g_sequence_sort_changed       (GSequenceIter            *iter, +                                              GCompareDataFunc          cmp_func, +                                              gpointer                  cmp_data); +void           g_sequence_sort_changed_iter  (GSequenceIter            *iter, +                                              GSequenceIterCompareFunc  iter_cmp, +                                              gpointer                  cmp_data); +void           g_sequence_remove             (GSequenceIter            *iter); +void           g_sequence_remove_range       (GSequenceIter            *begin, +                                              GSequenceIter            *end); +void           g_sequence_move_range         (GSequenceIter            *dest, +                                              GSequenceIter            *begin, +                                              GSequenceIter            *end); +GSequenceIter *g_sequence_search             (GSequence                *seq, +                                              gpointer                  data, +                                              GCompareDataFunc          cmp_func, +                                              gpointer                  cmp_data); +GSequenceIter *g_sequence_search_iter        (GSequence                *seq, +                                              gpointer                  data, +                                              GSequenceIterCompareFunc  iter_cmp, +                                              gpointer                  cmp_data); + + +/* Dereferencing */ +gpointer       g_sequence_get                (GSequenceIter            *iter); +void           g_sequence_set                (GSequenceIter            *iter, +                                              gpointer                  data); + +/* Operations on GSequenceIter * */ +gboolean       g_sequence_iter_is_begin      (GSequenceIter            *iter); +gboolean       g_sequence_iter_is_end        (GSequenceIter            *iter); +GSequenceIter *g_sequence_iter_next          (GSequenceIter            *iter); +GSequenceIter *g_sequence_iter_prev          (GSequenceIter            *iter); +gint           g_sequence_iter_get_position  (GSequenceIter            *iter); +GSequenceIter *g_sequence_iter_move          (GSequenceIter            *iter, +                                              gint                      delta); +GSequence *    g_sequence_iter_get_sequence  (GSequenceIter            *iter); + + +/* Search */ +gint           g_sequence_iter_compare       (GSequenceIter            *a, +                                              GSequenceIter            *b); +GSequenceIter *g_sequence_range_get_midpoint (GSequenceIter            *begin, +                                              GSequenceIter            *end); + +G_END_DECLS + +#endif /* __G_SEQUENCE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gshell.h b/protocols/Sametime/src/glib/include/glib/gshell.h new file mode 100644 index 0000000000..130f1008c8 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gshell.h @@ -0,0 +1,55 @@ +/* gshell.h - Shell-related utilities + * + *  Copyright 2000 Red Hat, Inc. + * + * GLib is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * GLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with GLib; see the file COPYING.LIB.  If not, write + * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_SHELL_H__ +#define __G_SHELL_H__ + +#include <glib/gerror.h> + +G_BEGIN_DECLS + +#define G_SHELL_ERROR g_shell_error_quark () + +typedef enum +{ +  /* mismatched or otherwise mangled quoting */ +  G_SHELL_ERROR_BAD_QUOTING, +  /* string to be parsed was empty */ +  G_SHELL_ERROR_EMPTY_STRING, +  G_SHELL_ERROR_FAILED +} GShellError; + +GQuark g_shell_error_quark (void); + +gchar*   g_shell_quote      (const gchar   *unquoted_string); +gchar*   g_shell_unquote    (const gchar   *quoted_string, +                             GError       **error); +gboolean g_shell_parse_argv (const gchar   *command_line, +                             gint          *argcp, +                             gchar       ***argvp, +                             GError       **error); + +G_END_DECLS + +#endif /* __G_SHELL_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gslice.h b/protocols/Sametime/src/glib/include/glib/gslice.h new file mode 100644 index 0000000000..962199e099 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gslice.h @@ -0,0 +1,86 @@ +/* GLIB sliced memory - fast threaded memory chunk allocator + * Copyright (C) 2005 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_SLICE_H__ +#define __G_SLICE_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +/* slices - fast allocation/release of small memory blocks + */ +gpointer g_slice_alloc          	(gsize	       block_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); +gpointer g_slice_alloc0         	(gsize         block_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); +gpointer g_slice_copy                   (gsize         block_size, +                                         gconstpointer mem_block) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); +void     g_slice_free1          	(gsize         block_size, +					 gpointer      mem_block); +void     g_slice_free_chain_with_offset (gsize         block_size, +					 gpointer      mem_chain, +					 gsize         next_offset); +#define  g_slice_new(type)      ((type*) g_slice_alloc (sizeof (type))) +#define  g_slice_new0(type)     ((type*) g_slice_alloc0 (sizeof (type))) +/* MemoryBlockType * + *       g_slice_dup                    (MemoryBlockType, + *	                                 MemoryBlockType *mem_block); + *       g_slice_free                   (MemoryBlockType, + *	                                 MemoryBlockType *mem_block); + *       g_slice_free_chain             (MemoryBlockType, + *                                       MemoryBlockType *first_chain_block, + *                                       memory_block_next_field); + * pseudo prototypes for the macro + * definitions following below. + */ + +/* we go through extra hoops to ensure type safety */ +#define g_slice_dup(type, mem)                                  \ +  (1 ? (type*) g_slice_copy (sizeof (type), (mem))              \ +     : ((void) ((type*) 0 == (mem)), (type*) 0)) +#define g_slice_free(type, mem)				do {	\ +  if (1) g_slice_free1 (sizeof (type), (mem));			\ +  else   (void) ((type*) 0 == (mem)); 				\ +} while (0) +#define g_slice_free_chain(type, mem_chain, next)	do {	\ +  if (1) g_slice_free_chain_with_offset (sizeof (type),		\ +                 (mem_chain), G_STRUCT_OFFSET (type, next)); 	\ +  else   (void) ((type*) 0 == (mem_chain));			\ +} while (0) + + +/* --- internal debugging API --- */ +typedef enum { +  G_SLICE_CONFIG_ALWAYS_MALLOC = 1, +  G_SLICE_CONFIG_BYPASS_MAGAZINES, +  G_SLICE_CONFIG_WORKING_SET_MSECS, +  G_SLICE_CONFIG_COLOR_INCREMENT, +  G_SLICE_CONFIG_CHUNK_SIZES, +  G_SLICE_CONFIG_CONTENTION_COUNTER +} GSliceConfig; +void     g_slice_set_config	   (GSliceConfig ckey, gint64 value); +gint64   g_slice_get_config	   (GSliceConfig ckey); +gint64*  g_slice_get_config_state  (GSliceConfig ckey, gint64 address, guint *n_values); + +G_END_DECLS + +#endif /* __G_SLICE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gslist.h b/protocols/Sametime/src/glib/include/glib/gslist.h new file mode 100644 index 0000000000..8b01faf5cd --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gslist.h @@ -0,0 +1,114 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_SLIST_H__ +#define __G_SLIST_H__ + +#include <glib/gmem.h> + +G_BEGIN_DECLS + +typedef struct _GSList GSList; + +struct _GSList +{ +  gpointer data; +  GSList *next; +}; + +/* Singly linked lists + */ +GSList*  g_slist_alloc                   (void) G_GNUC_WARN_UNUSED_RESULT; +void     g_slist_free                    (GSList           *list); +void     g_slist_free_1                  (GSList           *list); +#define	 g_slist_free1		         g_slist_free_1 +GSList*  g_slist_append                  (GSList           *list, +					  gpointer          data) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_prepend                 (GSList           *list, +					  gpointer          data) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_insert                  (GSList           *list, +					  gpointer          data, +					  gint              position) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_insert_sorted           (GSList           *list, +					  gpointer          data, +					  GCompareFunc      func) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_insert_sorted_with_data (GSList           *list, +					  gpointer          data, +					  GCompareDataFunc  func, +					  gpointer          user_data) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_insert_before           (GSList           *slist, +					  GSList           *sibling, +					  gpointer          data) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_concat                  (GSList           *list1, +					  GSList           *list2) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_remove                  (GSList           *list, +					  gconstpointer     data) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_remove_all              (GSList           *list, +					  gconstpointer     data) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_remove_link             (GSList           *list, +					  GSList           *link_) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_delete_link             (GSList           *list, +					  GSList           *link_) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_reverse                 (GSList           *list) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_copy                    (GSList           *list) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_nth                     (GSList           *list, +					  guint             n); +GSList*  g_slist_find                    (GSList           *list, +					  gconstpointer     data); +GSList*  g_slist_find_custom             (GSList           *list, +					  gconstpointer     data, +					  GCompareFunc      func); +gint     g_slist_position                (GSList           *list, +					  GSList           *llink); +gint     g_slist_index                   (GSList           *list, +					  gconstpointer     data); +GSList*  g_slist_last                    (GSList           *list); +guint    g_slist_length                  (GSList           *list); +void     g_slist_foreach                 (GSList           *list, +					  GFunc             func, +					  gpointer          user_data); +GSList*  g_slist_sort                    (GSList           *list, +					  GCompareFunc      compare_func) G_GNUC_WARN_UNUSED_RESULT; +GSList*  g_slist_sort_with_data          (GSList           *list, +					  GCompareDataFunc  compare_func, +					  gpointer          user_data) G_GNUC_WARN_UNUSED_RESULT; +gpointer g_slist_nth_data                (GSList           *list, +					  guint             n); + +#define  g_slist_next(slist)	         ((slist) ? (((GSList *)(slist))->next) : NULL) + +#ifndef G_DISABLE_DEPRECATED +void     g_slist_push_allocator          (gpointer	   dummy); +void     g_slist_pop_allocator           (void); +#endif + +G_END_DECLS + +#endif /* __G_SLIST_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gspawn.h b/protocols/Sametime/src/glib/include/glib/gspawn.h new file mode 100644 index 0000000000..9836b34242 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gspawn.h @@ -0,0 +1,139 @@ +/* gspawn.h - Process launching + * + *  Copyright 2000 Red Hat, Inc. + * + * GLib is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * GLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with GLib; see the file COPYING.LIB.  If not, write + * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_SPAWN_H__ +#define __G_SPAWN_H__ + +#include <glib/gerror.h> + +G_BEGIN_DECLS + +/* I'm not sure I remember our proposed naming convention here. */ +#define G_SPAWN_ERROR g_spawn_error_quark () + +typedef enum +{ +  G_SPAWN_ERROR_FORK,   /* fork failed due to lack of memory */ +  G_SPAWN_ERROR_READ,   /* read or select on pipes failed */ +  G_SPAWN_ERROR_CHDIR,  /* changing to working dir failed */ +  G_SPAWN_ERROR_ACCES,  /* execv() returned EACCES */ +  G_SPAWN_ERROR_PERM,   /* execv() returned EPERM */ +  G_SPAWN_ERROR_2BIG,   /* execv() returned E2BIG */ +  G_SPAWN_ERROR_NOEXEC, /* execv() returned ENOEXEC */ +  G_SPAWN_ERROR_NAMETOOLONG, /* ""  "" ENAMETOOLONG */ +  G_SPAWN_ERROR_NOENT,       /* ""  "" ENOENT */ +  G_SPAWN_ERROR_NOMEM,       /* ""  "" ENOMEM */ +  G_SPAWN_ERROR_NOTDIR,      /* ""  "" ENOTDIR */ +  G_SPAWN_ERROR_LOOP,        /* ""  "" ELOOP   */ +  G_SPAWN_ERROR_TXTBUSY,     /* ""  "" ETXTBUSY */ +  G_SPAWN_ERROR_IO,          /* ""  "" EIO */ +  G_SPAWN_ERROR_NFILE,       /* ""  "" ENFILE */ +  G_SPAWN_ERROR_MFILE,       /* ""  "" EMFLE */ +  G_SPAWN_ERROR_INVAL,       /* ""  "" EINVAL */ +  G_SPAWN_ERROR_ISDIR,       /* ""  "" EISDIR */ +  G_SPAWN_ERROR_LIBBAD,      /* ""  "" ELIBBAD */ +  G_SPAWN_ERROR_FAILED       /* other fatal failure, error->message +                              * should explain +                              */ +} GSpawnError; + +typedef void (* GSpawnChildSetupFunc) (gpointer user_data); + +typedef enum +{ +  G_SPAWN_LEAVE_DESCRIPTORS_OPEN = 1 << 0, +  G_SPAWN_DO_NOT_REAP_CHILD      = 1 << 1, +  /* look for argv[0] in the path i.e. use execvp() */ +  G_SPAWN_SEARCH_PATH            = 1 << 2, +  /* Dump output to /dev/null */ +  G_SPAWN_STDOUT_TO_DEV_NULL     = 1 << 3, +  G_SPAWN_STDERR_TO_DEV_NULL     = 1 << 4, +  G_SPAWN_CHILD_INHERITS_STDIN   = 1 << 5, +  G_SPAWN_FILE_AND_ARGV_ZERO     = 1 << 6 +} GSpawnFlags; + +GQuark g_spawn_error_quark (void); + +#ifdef G_OS_WIN32 +#define g_spawn_async g_spawn_async_utf8 +#define g_spawn_async_with_pipes g_spawn_async_with_pipes_utf8 +#define g_spawn_sync g_spawn_sync_utf8 +#define g_spawn_command_line_sync g_spawn_command_line_sync_utf8 +#define g_spawn_command_line_async g_spawn_command_line_async_utf8 +#endif + +gboolean g_spawn_async (const gchar           *working_directory, +                        gchar                **argv, +                        gchar                **envp, +                        GSpawnFlags            flags, +                        GSpawnChildSetupFunc   child_setup, +                        gpointer               user_data, +                        GPid                  *child_pid, +                        GError               **error); + + +/* Opens pipes for non-NULL standard_output, standard_input, standard_error, + * and returns the parent's end of the pipes. + */ +gboolean g_spawn_async_with_pipes (const gchar          *working_directory, +                                   gchar               **argv, +                                   gchar               **envp, +                                   GSpawnFlags           flags, +                                   GSpawnChildSetupFunc  child_setup, +                                   gpointer              user_data, +                                   GPid                 *child_pid, +                                   gint                 *standard_input, +                                   gint                 *standard_output, +                                   gint                 *standard_error, +                                   GError              **error); + + +/* If standard_output or standard_error are non-NULL, the full + * standard output or error of the command will be placed there. + */ + +gboolean g_spawn_sync         (const gchar          *working_directory, +                               gchar               **argv, +                               gchar               **envp, +                               GSpawnFlags           flags, +                               GSpawnChildSetupFunc  child_setup, +                               gpointer              user_data, +                               gchar               **standard_output, +                               gchar               **standard_error, +                               gint                 *exit_status, +                               GError              **error); + +gboolean g_spawn_command_line_sync  (const gchar          *command_line, +                                     gchar               **standard_output, +                                     gchar               **standard_error, +                                     gint                 *exit_status, +                                     GError              **error); +gboolean g_spawn_command_line_async (const gchar          *command_line, +                                     GError              **error); + +void g_spawn_close_pid (GPid pid); + +G_END_DECLS + +#endif /* __G_SPAWN_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gstrfuncs.h b/protocols/Sametime/src/glib/include/glib/gstrfuncs.h new file mode 100644 index 0000000000..5c7332a3c4 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gstrfuncs.h @@ -0,0 +1,269 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_STRFUNCS_H__ +#define __G_STRFUNCS_H__ + +#include <stdarg.h> +#include <glib/gmacros.h> +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +/* Functions like the ones in <ctype.h> that are not affected by locale. */ +typedef enum { +  G_ASCII_ALNUM  = 1 << 0, +  G_ASCII_ALPHA  = 1 << 1, +  G_ASCII_CNTRL  = 1 << 2, +  G_ASCII_DIGIT  = 1 << 3, +  G_ASCII_GRAPH  = 1 << 4, +  G_ASCII_LOWER  = 1 << 5, +  G_ASCII_PRINT  = 1 << 6, +  G_ASCII_PUNCT  = 1 << 7, +  G_ASCII_SPACE  = 1 << 8, +  G_ASCII_UPPER  = 1 << 9, +  G_ASCII_XDIGIT = 1 << 10 +} GAsciiType; + +GLIB_VAR const guint16 * const g_ascii_table; + +#define g_ascii_isalnum(c) \ +  ((g_ascii_table[(guchar) (c)] & G_ASCII_ALNUM) != 0) + +#define g_ascii_isalpha(c) \ +  ((g_ascii_table[(guchar) (c)] & G_ASCII_ALPHA) != 0) + +#define g_ascii_iscntrl(c) \ +  ((g_ascii_table[(guchar) (c)] & G_ASCII_CNTRL) != 0) + +#define g_ascii_isdigit(c) \ +  ((g_ascii_table[(guchar) (c)] & G_ASCII_DIGIT) != 0) + +#define g_ascii_isgraph(c) \ +  ((g_ascii_table[(guchar) (c)] & G_ASCII_GRAPH) != 0) + +#define g_ascii_islower(c) \ +  ((g_ascii_table[(guchar) (c)] & G_ASCII_LOWER) != 0) + +#define g_ascii_isprint(c) \ +  ((g_ascii_table[(guchar) (c)] & G_ASCII_PRINT) != 0) + +#define g_ascii_ispunct(c) \ +  ((g_ascii_table[(guchar) (c)] & G_ASCII_PUNCT) != 0) + +#define g_ascii_isspace(c) \ +  ((g_ascii_table[(guchar) (c)] & G_ASCII_SPACE) != 0) + +#define g_ascii_isupper(c) \ +  ((g_ascii_table[(guchar) (c)] & G_ASCII_UPPER) != 0) + +#define g_ascii_isxdigit(c) \ +  ((g_ascii_table[(guchar) (c)] & G_ASCII_XDIGIT) != 0) + +gchar                 g_ascii_tolower  (gchar        c) G_GNUC_CONST; +gchar                 g_ascii_toupper  (gchar        c) G_GNUC_CONST; + +gint                  g_ascii_digit_value  (gchar    c) G_GNUC_CONST; +gint                  g_ascii_xdigit_value (gchar    c) G_GNUC_CONST; + +/* String utility functions that modify a string argument or + * return a constant string that must not be freed. + */ +#define	 G_STR_DELIMITERS	"_-|> <." +gchar*	              g_strdelimit     (gchar	     *string, +					const gchar  *delimiters, +					gchar	      new_delimiter); +gchar*	              g_strcanon       (gchar        *string, +					const gchar  *valid_chars, +					gchar         substitutor); +G_CONST_RETURN gchar* g_strerror       (gint	      errnum) G_GNUC_CONST; +G_CONST_RETURN gchar* g_strsignal      (gint	      signum) G_GNUC_CONST; +gchar*	              g_strreverse     (gchar	     *string); +gsize	              g_strlcpy	       (gchar	     *dest, +					const gchar  *src, +					gsize         dest_size); +gsize	              g_strlcat        (gchar	     *dest, +					const gchar  *src, +					gsize         dest_size); +gchar *               g_strstr_len     (const gchar  *haystack, +					gssize        haystack_len, +					const gchar  *needle); +gchar *               g_strrstr        (const gchar  *haystack, +					const gchar  *needle); +gchar *               g_strrstr_len    (const gchar  *haystack, +					gssize        haystack_len, +					const gchar  *needle); + +gboolean              g_str_has_suffix (const gchar  *str, +					const gchar  *suffix); +gboolean              g_str_has_prefix (const gchar  *str, +					const gchar  *prefix); + +/* String to/from double conversion functions */ + +gdouble	              g_strtod         (const gchar  *nptr, +					gchar	    **endptr); +gdouble	              g_ascii_strtod   (const gchar  *nptr, +					gchar	    **endptr); +guint64		      g_ascii_strtoull (const gchar *nptr, +					gchar      **endptr, +					guint        base); +gint64		      g_ascii_strtoll  (const gchar *nptr, +					gchar      **endptr, +					guint        base); +/* 29 bytes should enough for all possible values that + * g_ascii_dtostr can produce. + * Then add 10 for good measure */ +#define G_ASCII_DTOSTR_BUF_SIZE (29 + 10) +gchar *               g_ascii_dtostr   (gchar        *buffer, +					gint          buf_len, +					gdouble       d); +gchar *               g_ascii_formatd  (gchar        *buffer, +					gint          buf_len, +					const gchar  *format, +					gdouble       d); + +/* removes leading spaces */ +gchar*                g_strchug        (gchar        *string); +/* removes trailing spaces */ +gchar*                g_strchomp       (gchar        *string); +/* removes leading & trailing spaces */ +#define g_strstrip( string )	g_strchomp (g_strchug (string)) + +gint                  g_ascii_strcasecmp  (const gchar *s1, +					   const gchar *s2); +gint                  g_ascii_strncasecmp (const gchar *s1, +					   const gchar *s2, +					   gsize        n); +gchar*                g_ascii_strdown     (const gchar *str, +					   gssize       len) G_GNUC_MALLOC; +gchar*                g_ascii_strup       (const gchar *str, +					   gssize       len) G_GNUC_MALLOC; + +#ifndef G_DISABLE_DEPRECATED + +/* The following four functions are deprecated and will be removed in + * the next major release. They use the locale-specific tolower and + * toupper, which is almost never the right thing. + */ + +gint	              g_strcasecmp     (const gchar *s1, +					const gchar *s2); +gint	              g_strncasecmp    (const gchar *s1, +					const gchar *s2, +					guint        n); +gchar*	              g_strdown	       (gchar	     *string); +gchar*	              g_strup	       (gchar	     *string); + +#endif /* G_DISABLE_DEPRECATED */ + +/* String utility functions that return a newly allocated string which + * ought to be freed with g_free from the caller at some point. + */ +gchar*	              g_strdup	       (const gchar *str) G_GNUC_MALLOC; +gchar*	              g_strdup_printf  (const gchar *format, +					...) G_GNUC_PRINTF (1, 2) G_GNUC_MALLOC; +gchar*	              g_strdup_vprintf (const gchar *format, +					va_list      args) G_GNUC_MALLOC; +gchar*	              g_strndup	       (const gchar *str, +					gsize        n) G_GNUC_MALLOC;   +gchar*	              g_strnfill       (gsize        length,   +					gchar        fill_char) G_GNUC_MALLOC; +gchar*	              g_strconcat      (const gchar *string1, +					...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED; +gchar*                g_strjoin	       (const gchar  *separator, +					...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED; + +/* Make a copy of a string interpreting C string -style escape + * sequences. Inverse of g_strescape. The recognized sequences are \b + * \f \n \r \t \\ \" and the octal format. + */ +gchar*                g_strcompress    (const gchar *source) G_GNUC_MALLOC; + +/* Copy a string escaping nonprintable characters like in C strings. + * Inverse of g_strcompress. The exceptions parameter, if non-NULL, points + * to a string containing characters that are not to be escaped. + * + * Deprecated API: gchar* g_strescape (const gchar *source); + * Luckily this function wasn't used much, using NULL as second parameter + * provides mostly identical semantics. + */ +gchar*                g_strescape      (const gchar *source, +					const gchar *exceptions) G_GNUC_MALLOC; + +gpointer              g_memdup	       (gconstpointer mem, +					guint	       byte_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(2); + +/* NULL terminated string arrays. + * g_strsplit(), g_strsplit_set() split up string into max_tokens tokens + * at delim and return a newly allocated string array. + * g_strjoinv() concatenates all of str_array's strings, sliding in an + * optional separator, the returned string is newly allocated. + * g_strfreev() frees the array itself and all of its strings. + * g_strdupv() copies a NULL-terminated array of strings + * g_strv_length() returns the length of a NULL-terminated array of strings + */ +gchar**	              g_strsplit       (const gchar  *string, +					const gchar  *delimiter, +					gint          max_tokens) G_GNUC_MALLOC; +gchar **	      g_strsplit_set   (const gchar *string, +					const gchar *delimiters, +					gint         max_tokens) G_GNUC_MALLOC; +gchar*                g_strjoinv       (const gchar  *separator, +					gchar       **str_array) G_GNUC_MALLOC; +void                  g_strfreev       (gchar       **str_array); +gchar**               g_strdupv        (gchar       **str_array) G_GNUC_MALLOC; +guint                 g_strv_length    (gchar       **str_array); + +gchar*                g_stpcpy         (gchar        *dest, +                                        const char   *src); + +G_CONST_RETURN gchar *g_strip_context  (const gchar *msgid,  +					const gchar *msgval) G_GNUC_FORMAT(1); + +G_CONST_RETURN gchar *g_dgettext       (const gchar *domain, +					const gchar *msgid) G_GNUC_FORMAT(2); +G_CONST_RETURN gchar *g_dcgettext      (const gchar *domain, +					const gchar *msgid, +                                        int          category) G_GNUC_FORMAT(2); +G_CONST_RETURN gchar *g_dngettext      (const gchar *domain, +					const gchar *msgid, +					const gchar *msgid_plural, +					gulong       n) G_GNUC_FORMAT(3); +G_CONST_RETURN gchar *g_dpgettext      (const gchar *domain, +                                        const gchar *msgctxtid, +                                        gsize        msgidoffset) G_GNUC_FORMAT(2); +G_CONST_RETURN gchar *g_dpgettext2     (const gchar *domain, +                                        const gchar *context, +                                        const gchar *msgid) G_GNUC_FORMAT(3); + +G_END_DECLS + +#endif /* __G_STRFUNCS_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gstring.h b/protocols/Sametime/src/glib/include/glib/gstring.h new file mode 100644 index 0000000000..2b1dd6ece2 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gstring.h @@ -0,0 +1,178 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_STRING_H__ +#define __G_STRING_H__ + +#include <glib/gtypes.h> +#include <glib/gunicode.h> +#include <glib/gutils.h>  /* for G_CAN_INLINE */ + +G_BEGIN_DECLS + +typedef struct _GString		GString; +typedef struct _GStringChunk	GStringChunk; + +struct _GString +{ +  gchar  *str; +  gsize len;     +  gsize allocated_len; +}; + +/* String Chunks + */ +GStringChunk* g_string_chunk_new	   (gsize size);   +void	      g_string_chunk_free	   (GStringChunk *chunk); +void	      g_string_chunk_clear	   (GStringChunk *chunk); +gchar*	      g_string_chunk_insert	   (GStringChunk *chunk, +					    const gchar	 *string); +gchar*	      g_string_chunk_insert_len	   (GStringChunk *chunk, +					    const gchar	 *string, +					    gssize        len); +gchar*	      g_string_chunk_insert_const  (GStringChunk *chunk, +					    const gchar	 *string); + + +/* Strings + */ +GString*     g_string_new	        (const gchar	 *init); +GString*     g_string_new_len           (const gchar     *init, +                                         gssize           len);    +GString*     g_string_sized_new         (gsize            dfl_size);   +gchar*	     g_string_free	        (GString	 *string, +					 gboolean	  free_segment); +gboolean     g_string_equal             (const GString	 *v, +					 const GString 	 *v2); +guint        g_string_hash              (const GString   *str); +GString*     g_string_assign            (GString	 *string, +					 const gchar	 *rval); +GString*     g_string_truncate          (GString	 *string, +					 gsize		  len);     +GString*     g_string_set_size          (GString         *string, +					 gsize            len); +GString*     g_string_insert_len        (GString         *string, +                                         gssize           pos,    +                                         const gchar     *val, +                                         gssize           len);   +GString*     g_string_append            (GString	 *string, +			                 const gchar	 *val); +GString*     g_string_append_len        (GString	 *string, +			                 const gchar	 *val, +                                         gssize           len);   +GString*     g_string_append_c          (GString	 *string, +					 gchar		  c); +GString*     g_string_append_unichar    (GString	 *string, +					 gunichar	  wc); +GString*     g_string_prepend           (GString	 *string, +					 const gchar	 *val); +GString*     g_string_prepend_c         (GString	 *string, +					 gchar		  c); +GString*     g_string_prepend_unichar   (GString	 *string, +					 gunichar	  wc); +GString*     g_string_prepend_len       (GString	 *string, +			                 const gchar	 *val, +                                         gssize           len);   +GString*     g_string_insert            (GString	 *string, +					 gssize		  pos,     +					 const gchar	 *val); +GString*     g_string_insert_c          (GString	 *string, +					 gssize		  pos,     +					 gchar		  c); +GString*     g_string_insert_unichar    (GString	 *string, +					 gssize		  pos,     +					 gunichar	  wc); +GString*     g_string_overwrite         (GString	 *string, +					 gsize		  pos,     +					 const gchar	 *val); +GString*     g_string_overwrite_len     (GString	 *string, +					 gsize		  pos,     +					 const gchar	 *val, +					 gssize           len); +GString*     g_string_erase	        (GString	 *string, +					 gssize		  pos, +					 gssize		  len); +GString*     g_string_ascii_down        (GString	 *string); +GString*     g_string_ascii_up          (GString	 *string); +void         g_string_vprintf           (GString	 *string, +					 const gchar	 *format, +					 va_list          args); +void         g_string_printf            (GString	 *string, +					 const gchar	 *format, +					 ...) G_GNUC_PRINTF (2, 3); +void         g_string_append_vprintf    (GString	 *string, +					 const gchar	 *format, +					 va_list          args); +void         g_string_append_printf     (GString	 *string, +					 const gchar	 *format, +					 ...) G_GNUC_PRINTF (2, 3); +GString *    g_string_append_uri_escaped(GString         *string, +					 const char      *unescaped, +					 const char      *reserved_chars_allowed, +					 gboolean         allow_utf8); + +/* -- optimize g_strig_append_c --- */ +#ifdef G_CAN_INLINE +static inline GString* +g_string_append_c_inline (GString *gstring, +                          gchar    c) +{ +  if (gstring->len + 1 < gstring->allocated_len) +    { +      gstring->str[gstring->len++] = c; +      gstring->str[gstring->len] = 0; +    } +  else +    g_string_insert_c (gstring, -1, c); +  return gstring; +} +#define g_string_append_c(gstr,c)       g_string_append_c_inline (gstr, c) +#endif /* G_CAN_INLINE */ + + +#ifndef G_DISABLE_DEPRECATED + +/* The following two functions are deprecated and will be removed in + * the next major release. They use the locale-specific tolower and + * toupper, which is almost never the right thing. + */ + +GString*     g_string_down              (GString	 *string); +GString*     g_string_up                (GString	 *string); + +/* These aliases are included for compatibility. */ +#define	g_string_sprintf	g_string_printf +#define	g_string_sprintfa	g_string_append_printf + +#endif /* G_DISABLE_DEPRECATED */ + +G_END_DECLS + +#endif /* __G_STRING_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gtestutils.h b/protocols/Sametime/src/glib/include/glib/gtestutils.h new file mode 100644 index 0000000000..b441fe08bc --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gtestutils.h @@ -0,0 +1,297 @@ +/* GLib testing utilities + * Copyright (C) 2007 Imendio AB + * Authors: Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_TEST_UTILS_H__ +#define __G_TEST_UTILS_H__ + +#include <glib/gmessages.h> +#include <glib/gstring.h> +#include <glib/gerror.h> +#include <glib/gslist.h> + +G_BEGIN_DECLS + +typedef struct GTestCase  GTestCase; +typedef struct GTestSuite GTestSuite; +typedef void (*GTestFunc)        (void); +typedef void (*GTestDataFunc)    (gconstpointer user_data); +typedef void (*GTestFixtureFunc) (gpointer      fixture, +                                  gconstpointer user_data); + +/* assertion API */ +#define g_assert_cmpstr(s1, cmp, s2)    do { const char *__s1 = (s1), *__s2 = (s2); \ +                                             if (g_strcmp0 (__s1, __s2) cmp 0) ; else \ +                                               g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ +                                                 #s1 " " #cmp " " #s2, __s1, #cmp, __s2); } while (0) +#define g_assert_cmpint(n1, cmp, n2)    do { gint64 __n1 = (n1), __n2 = (n2); \ +                                             if (__n1 cmp __n2) ; else \ +                                               g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ +                                                 #n1 " " #cmp " " #n2, __n1, #cmp, __n2, 'i'); } while (0) +#define g_assert_cmpuint(n1, cmp, n2)   do { guint64 __n1 = (n1), __n2 = (n2); \ +                                             if (__n1 cmp __n2) ; else \ +                                               g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ +                                                 #n1 " " #cmp " " #n2, __n1, #cmp, __n2, 'i'); } while (0) +#define g_assert_cmphex(n1, cmp, n2)    do { guint64 __n1 = (n1), __n2 = (n2); \ +                                             if (__n1 cmp __n2) ; else \ +                                               g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ +                                                 #n1 " " #cmp " " #n2, __n1, #cmp, __n2, 'x'); } while (0) +#define g_assert_cmpfloat(n1,cmp,n2)    do { long double __n1 = (n1), __n2 = (n2); \ +                                             if (__n1 cmp __n2) ; else \ +                                               g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ +                                                 #n1 " " #cmp " " #n2, __n1, #cmp, __n2, 'f'); } while (0) +#define g_assert_no_error(err)          do { if (err) \ +                                               g_assertion_message_error (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ +                                                 #err, err, 0, 0); } while (0) +#define g_assert_error(err, dom, c)	do { if (!err || (err)->domain != dom || (err)->code != c) \ +                                               g_assertion_message_error (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ +                                                 #err, err, dom, c); } while (0) +#ifdef G_DISABLE_ASSERT +#define g_assert_not_reached()          do { (void) 0; } while (0) +#define g_assert(expr)                  do { (void) 0; } while (0) +#else /* !G_DISABLE_ASSERT */ +#define g_assert_not_reached()          do { g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, NULL); } while (0) +#define g_assert(expr)                  do { if G_LIKELY (expr) ; else \ +                                               g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ +                                                 #expr); } while (0) +#endif /* !G_DISABLE_ASSERT */ + +int     g_strcmp0                       (const char     *str1, +                                         const char     *str2); + +/* report performance results */ +void    g_test_minimized_result         (double          minimized_quantity, +                                         const char     *format, +                                         ...) G_GNUC_PRINTF (2, 3); +void    g_test_maximized_result         (double          maximized_quantity, +                                         const char     *format, +                                         ...) G_GNUC_PRINTF (2, 3); + +/* initialize testing framework */ +void    g_test_init                     (int            *argc, +                                         char         ***argv, +                                         ...); +/* query testing framework config */ +#define g_test_quick()                  (g_test_config_vars->test_quick) +#define g_test_slow()                   (!g_test_config_vars->test_quick) +#define g_test_thorough()               (!g_test_config_vars->test_quick) +#define g_test_perf()                   (g_test_config_vars->test_perf) +#define g_test_verbose()                (g_test_config_vars->test_verbose) +#define g_test_quiet()                  (g_test_config_vars->test_quiet) +/* run all tests under toplevel suite (path: /) */ +int     g_test_run                      (void); +/* hook up a test functions under test path */ +void    g_test_add_func                 (const char     *testpath, +                                         GTestFunc       test_func); + +void    g_test_add_data_func            (const char     *testpath, +                                         gconstpointer   test_data, +                                         GTestDataFunc   test_func); + +/* hook up a test with fixture under test path */ +#define g_test_add(testpath, Fixture, tdata, fsetup, ftest, fteardown) \ +					G_STMT_START {			\ +                                         void (*add_vtable) (const char*,       \ +                                                    gsize,             \ +                                                    gconstpointer,     \ +                                                    void (*) (Fixture*, gconstpointer),   \ +                                                    void (*) (Fixture*, gconstpointer),   \ +                                                    void (*) (Fixture*, gconstpointer)) =  (void (*) (const gchar *, gsize, gconstpointer, void (*) (Fixture*, gconstpointer), void (*) (Fixture*, gconstpointer), void (*) (Fixture*, gconstpointer))) g_test_add_vtable; \ +                                         add_vtable \ +                                          (testpath, sizeof (Fixture), tdata, fsetup, ftest, fteardown); \ +					} G_STMT_END + +/* add test messages to the test report */ +void    g_test_message                  (const char *format, +                                         ...) G_GNUC_PRINTF (1, 2); +void    g_test_bug_base                 (const char *uri_pattern); +void    g_test_bug                      (const char *bug_uri_snippet); +/* measure test timings */ +void    g_test_timer_start              (void); +double  g_test_timer_elapsed            (void); /* elapsed seconds */ +double  g_test_timer_last               (void); /* repeat last elapsed() result */ + +/* automatically g_free or g_object_unref upon teardown */ +void    g_test_queue_free               (gpointer gfree_pointer); +void    g_test_queue_destroy            (GDestroyNotify destroy_func, +                                         gpointer       destroy_data); +#define g_test_queue_unref(gobject)     g_test_queue_destroy (g_object_unref, gobject) + +/* test traps are guards used around forked tests */ +typedef enum { +  G_TEST_TRAP_SILENCE_STDOUT    = 1 << 7, +  G_TEST_TRAP_SILENCE_STDERR    = 1 << 8, +  G_TEST_TRAP_INHERIT_STDIN     = 1 << 9 +} GTestTrapFlags; +gboolean g_test_trap_fork               (guint64              usec_timeout, +                                         GTestTrapFlags       test_trap_flags); +gboolean g_test_trap_has_passed         (void); +gboolean g_test_trap_reached_timeout    (void); +#define  g_test_trap_assert_passed()                      g_test_trap_assertions (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 0, 0) +#define  g_test_trap_assert_failed()                      g_test_trap_assertions (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 1, 0) +#define  g_test_trap_assert_stdout(soutpattern)           g_test_trap_assertions (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 2, soutpattern) +#define  g_test_trap_assert_stdout_unmatched(soutpattern) g_test_trap_assertions (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 3, soutpattern) +#define  g_test_trap_assert_stderr(serrpattern)           g_test_trap_assertions (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 4, serrpattern) +#define  g_test_trap_assert_stderr_unmatched(serrpattern) g_test_trap_assertions (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 5, serrpattern) + +/* provide seed-able random numbers for tests */ +#define  g_test_rand_bit()              (0 != (g_test_rand_int() & (1 << 15))) +gint32   g_test_rand_int                (void); +gint32   g_test_rand_int_range          (gint32          begin, +                                         gint32          end); +double   g_test_rand_double             (void); +double   g_test_rand_double_range       (double          range_start, +                                         double          range_end); + +/* semi-internal API */ +GTestCase*    g_test_create_case        (const char       *test_name, +                                         gsize             data_size, +                                         gconstpointer     test_data, +                                         GTestFixtureFunc  data_setup, +                                         GTestFixtureFunc  data_test, +                                         GTestFixtureFunc  data_teardown); +GTestSuite*   g_test_create_suite       (const char       *suite_name); +GTestSuite*   g_test_get_root           (void); +void          g_test_suite_add          (GTestSuite     *suite, +                                         GTestCase      *test_case); +void          g_test_suite_add_suite    (GTestSuite     *suite, +                                         GTestSuite     *nestedsuite); +int           g_test_run_suite          (GTestSuite     *suite); + +/* internal ABI */ +void    g_test_trap_assertions          (const char     *domain, +                                         const char     *file, +                                         int             line, +                                         const char     *func, +                                         guint64         assertion_flags, /* 0-pass, 1-fail, 2-outpattern, 4-errpattern */ +                                         const char     *pattern); +void    g_assertion_message             (const char     *domain, +                                         const char     *file, +                                         int             line, +                                         const char     *func, +                                         const char     *message) G_GNUC_NORETURN; +void    g_assertion_message_expr        (const char     *domain, +                                         const char     *file, +                                         int             line, +                                         const char     *func, +                                         const char     *expr) G_GNUC_NORETURN; +void    g_assertion_message_cmpstr      (const char     *domain, +                                         const char     *file, +                                         int             line, +                                         const char     *func, +                                         const char     *expr, +                                         const char     *arg1, +                                         const char     *cmp, +                                         const char     *arg2) G_GNUC_NORETURN; +void    g_assertion_message_cmpnum      (const char     *domain, +                                         const char     *file, +                                         int             line, +                                         const char     *func, +                                         const char     *expr, +                                         long double     arg1, +                                         const char     *cmp, +                                         long double     arg2, +                                         char            numtype) G_GNUC_NORETURN; +void    g_assertion_message_error       (const char     *domain, +                                         const char     *file, +                                         int             line, +                                         const char     *func, +                                         const char     *expr, +                                         const GError   *error, +                                         GQuark          error_domain, +                                         int             error_code) G_GNUC_NORETURN; +void    g_test_add_vtable               (const char     *testpath, +                                         gsize           data_size, +                                         gconstpointer   test_data, +                                         GTestFixtureFunc  data_setup, +                                         GTestFixtureFunc  data_test, +                                         GTestFixtureFunc  data_teardown); +typedef struct { +  gboolean      test_initialized; +  gboolean      test_quick;     /* disable thorough tests */ +  gboolean      test_perf;      /* run performance tests */ +  gboolean      test_verbose;   /* extra info */ +  gboolean      test_quiet;     /* reduce output */ +} GTestConfig; +GLIB_VAR const GTestConfig * const g_test_config_vars; + +/* internal logging API */ +typedef enum { +  G_TEST_LOG_NONE, +  G_TEST_LOG_ERROR,             /* s:msg */ +  G_TEST_LOG_START_BINARY,      /* s:binaryname s:seed */ +  G_TEST_LOG_LIST_CASE,         /* s:testpath */ +  G_TEST_LOG_SKIP_CASE,         /* s:testpath */ +  G_TEST_LOG_START_CASE,        /* s:testpath */ +  G_TEST_LOG_STOP_CASE,         /* d:status d:nforks d:elapsed */ +  G_TEST_LOG_MIN_RESULT,        /* s:blurb d:result */ +  G_TEST_LOG_MAX_RESULT,        /* s:blurb d:result */ +  G_TEST_LOG_MESSAGE            /* s:blurb */ +} GTestLogType; + +typedef struct { +  GTestLogType  log_type; +  guint         n_strings; +  gchar       **strings; /* NULL terminated */ +  guint         n_nums; +  long double  *nums; +} GTestLogMsg; +typedef struct { +  /*< private >*/ +  GString     *data; +  GSList      *msgs; +} GTestLogBuffer; + +const char*     g_test_log_type_name    (GTestLogType    log_type); +GTestLogBuffer* g_test_log_buffer_new   (void); +void            g_test_log_buffer_free  (GTestLogBuffer *tbuffer); +void            g_test_log_buffer_push  (GTestLogBuffer *tbuffer, +                                         guint           n_bytes, +                                         const guint8   *bytes); +GTestLogMsg*    g_test_log_buffer_pop   (GTestLogBuffer *tbuffer); +void            g_test_log_msg_free     (GTestLogMsg    *tmsg); + +/** + * GTestLogFatalFunc: + * @log_domain: the log domain of the message + * @log_level: the log level of the message (including the fatal and recursion flags) + * @message: the message to process + * @user_data: user data, set in g_test_log_set_fatal_handler() + * + * Specifies the prototype of fatal log handler functions. + * + * Return value: %TRUE if the program should abort, %FALSE otherwise + * + * Since: 2.22 + */ +typedef gboolean        (*GTestLogFatalFunc)    (const gchar    *log_domain, +                                                 GLogLevelFlags  log_level, +                                                 const gchar    *message, +                                                 gpointer        user_data); +void +g_test_log_set_fatal_handler            (GTestLogFatalFunc log_func, +                                         gpointer          user_data); + +G_END_DECLS + +#endif /* __G_TEST_UTILS_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gthread.h b/protocols/Sametime/src/glib/include/glib/gthread.h new file mode 100644 index 0000000000..82d40c0b85 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gthread.h @@ -0,0 +1,407 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_THREAD_H__ +#define __G_THREAD_H__ + +#include <glib/gerror.h> +#include <glib/gutils.h>        /* for G_INLINE_FUNC */ +#include <glib/gatomic.h>       /* for g_atomic_pointer_get */ + +G_BEGIN_DECLS + +/* GLib Thread support + */ + +extern GQuark g_thread_error_quark (void); +#define G_THREAD_ERROR g_thread_error_quark () + +typedef enum +{ +  G_THREAD_ERROR_AGAIN /* Resource temporarily unavailable */ +} GThreadError; + +typedef gpointer (*GThreadFunc) (gpointer data); + +typedef enum +{ +  G_THREAD_PRIORITY_LOW, +  G_THREAD_PRIORITY_NORMAL, +  G_THREAD_PRIORITY_HIGH, +  G_THREAD_PRIORITY_URGENT +} GThreadPriority; + +typedef struct _GThread         GThread; +struct  _GThread +{ +  /*< private >*/ +  GThreadFunc func; +  gpointer data; +  gboolean joinable; +  GThreadPriority priority; +}; + +typedef struct _GMutex          GMutex; +typedef struct _GCond           GCond; +typedef struct _GPrivate        GPrivate; +typedef struct _GStaticPrivate  GStaticPrivate; + +typedef struct _GThreadFunctions GThreadFunctions; +struct _GThreadFunctions +{ +  GMutex*  (*mutex_new)           (void); +  void     (*mutex_lock)          (GMutex               *mutex); +  gboolean (*mutex_trylock)       (GMutex               *mutex); +  void     (*mutex_unlock)        (GMutex               *mutex); +  void     (*mutex_free)          (GMutex               *mutex); +  GCond*   (*cond_new)            (void); +  void     (*cond_signal)         (GCond                *cond); +  void     (*cond_broadcast)      (GCond                *cond); +  void     (*cond_wait)           (GCond                *cond, +                                   GMutex               *mutex); +  gboolean (*cond_timed_wait)     (GCond                *cond, +                                   GMutex               *mutex, +                                   GTimeVal             *end_time); +  void      (*cond_free)          (GCond                *cond); +  GPrivate* (*private_new)        (GDestroyNotify        destructor); +  gpointer  (*private_get)        (GPrivate             *private_key); +  void      (*private_set)        (GPrivate             *private_key, +                                   gpointer              data); +  void      (*thread_create)      (GThreadFunc           func, +                                   gpointer              data, +                                   gulong                stack_size, +                                   gboolean              joinable, +                                   gboolean              bound, +                                   GThreadPriority       priority, +                                   gpointer              thread, +                                   GError              **error); +  void      (*thread_yield)       (void); +  void      (*thread_join)        (gpointer              thread); +  void      (*thread_exit)        (void); +  void      (*thread_set_priority)(gpointer              thread, +                                   GThreadPriority       priority); +  void      (*thread_self)        (gpointer              thread); +  gboolean  (*thread_equal)       (gpointer              thread1, +				   gpointer              thread2); +}; + +GLIB_VAR GThreadFunctions       g_thread_functions_for_glib_use; +GLIB_VAR gboolean               g_thread_use_default_impl; +GLIB_VAR gboolean               g_threads_got_initialized; + +GLIB_VAR guint64   (*g_thread_gettime) (void); + +/* initializes the mutex/cond/private implementation for glib, might + * only be called once, and must not be called directly or indirectly + * from another glib-function, e.g. as a callback. + */ +void    g_thread_init   (GThreadFunctions       *vtable); + +/* Errorcheck mutexes. If you define G_ERRORCHECK_MUTEXES, then all + * mutexes will check for re-locking and re-unlocking */ + +/* Initialize thread system with errorcheck mutexes. vtable must be + * NULL. Do not call directly. Use #define G_ERRORCHECK_MUTEXES + * instead. + */ +void    g_thread_init_with_errorcheck_mutexes (GThreadFunctions* vtable); + +/* Checks if thread support is initialized.  Identical to the + * g_thread_supported macro but provided for language bindings. + */ +gboolean g_thread_get_initialized (void); + +/* A random number to recognize debug calls to g_mutex_... */ +#define G_MUTEX_DEBUG_MAGIC 0xf8e18ad7 + +#ifdef G_ERRORCHECK_MUTEXES +#define g_thread_init(vtable) g_thread_init_with_errorcheck_mutexes (vtable) +#endif + +/* internal function for fallback static mutex implementation */ +GMutex* g_static_mutex_get_mutex_impl   (GMutex **mutex); + +#define g_static_mutex_get_mutex_impl_shortcut(mutex) \ +  (g_atomic_pointer_get (mutex) ? *(mutex) : \ +   g_static_mutex_get_mutex_impl (mutex)) + +/* shorthands for conditional and unconditional function calls */ + +#define G_THREAD_UF(op, arglist)					\ +    (*g_thread_functions_for_glib_use . op) arglist +#define G_THREAD_CF(op, fail, arg)					\ +    (g_thread_supported () ? G_THREAD_UF (op, arg) : (fail)) +#define G_THREAD_ECF(op, fail, mutex, type)				\ +    (g_thread_supported () ? 						\ +      ((type(*)(GMutex*, const gulong, gchar const*))			\ +      (*g_thread_functions_for_glib_use . op))				\ +     (mutex, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : (fail)) + +#ifndef G_ERRORCHECK_MUTEXES +# define g_mutex_lock(mutex)						\ +    G_THREAD_CF (mutex_lock,     (void)0, (mutex)) +# define g_mutex_trylock(mutex)						\ +    G_THREAD_CF (mutex_trylock,  TRUE,    (mutex)) +# define g_mutex_unlock(mutex)						\ +    G_THREAD_CF (mutex_unlock,   (void)0, (mutex)) +# define g_mutex_free(mutex)						\ +    G_THREAD_CF (mutex_free,     (void)0, (mutex)) +# define g_cond_wait(cond, mutex)					\ +    G_THREAD_CF (cond_wait,      (void)0, (cond, mutex)) +# define g_cond_timed_wait(cond, mutex, abs_time)			\ +    G_THREAD_CF (cond_timed_wait, TRUE,   (cond, mutex, abs_time)) +#else /* G_ERRORCHECK_MUTEXES */ +# define g_mutex_lock(mutex)						\ +    G_THREAD_ECF (mutex_lock,    (void)0, (mutex), void) +# define g_mutex_trylock(mutex)						\ +    G_THREAD_ECF (mutex_trylock, TRUE,    (mutex), gboolean) +# define g_mutex_unlock(mutex)						\ +    G_THREAD_ECF (mutex_unlock,  (void)0, (mutex), void) +# define g_mutex_free(mutex)						\ +    G_THREAD_ECF (mutex_free,    (void)0, (mutex), void) +# define g_cond_wait(cond, mutex)					\ +    (g_thread_supported () ? ((void(*)(GCond*, GMutex*, gulong, gchar*))\ +      g_thread_functions_for_glib_use.cond_wait)			\ +        (cond, mutex, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : (void) 0) +# define g_cond_timed_wait(cond, mutex, abs_time)			\ +    (g_thread_supported () ?						\ +      ((gboolean(*)(GCond*, GMutex*, GTimeVal*, gulong, gchar*))	\ +        g_thread_functions_for_glib_use.cond_timed_wait)		\ +          (cond, mutex, abs_time, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : TRUE) +#endif /* G_ERRORCHECK_MUTEXES */ + +#if defined(G_THREADS_ENABLED) && defined(G_THREADS_MANDATORY) +#define g_thread_supported()     1 +#else +#define g_thread_supported()    (g_threads_got_initialized) +#endif +#define g_mutex_new()            G_THREAD_UF (mutex_new,      ()) +#define g_cond_new()             G_THREAD_UF (cond_new,       ()) +#define g_cond_signal(cond)      G_THREAD_CF (cond_signal,    (void)0, (cond)) +#define g_cond_broadcast(cond)   G_THREAD_CF (cond_broadcast, (void)0, (cond)) +#define g_cond_free(cond)        G_THREAD_CF (cond_free,      (void)0, (cond)) +#define g_private_new(destructor) G_THREAD_UF (private_new, (destructor)) +#define g_private_get(private_key) G_THREAD_CF (private_get, \ +                                                ((gpointer)private_key), \ +                                                (private_key)) +#define g_private_set(private_key, value) G_THREAD_CF (private_set, \ +                                                       (void) (private_key = \ +                                                        (GPrivate*) (value)), \ +                                                       (private_key, value)) +#define g_thread_yield()              G_THREAD_CF (thread_yield, (void)0, ()) + +#define g_thread_create(func, data, joinable, error)			\ +  (g_thread_create_full (func, data, 0, joinable, FALSE, 		\ +                         G_THREAD_PRIORITY_NORMAL, error)) + +GThread* g_thread_create_full  (GThreadFunc            func, +                                gpointer               data, +                                gulong                 stack_size, +                                gboolean               joinable, +                                gboolean               bound, +                                GThreadPriority        priority, +                                GError               **error); +GThread* g_thread_self         (void); +void     g_thread_exit         (gpointer               retval); +gpointer g_thread_join         (GThread               *thread); + +void     g_thread_set_priority (GThread               *thread, +                                GThreadPriority        priority); + +/* GStaticMutexes can be statically initialized with the value + * G_STATIC_MUTEX_INIT, and then they can directly be used, that is + * much easier, than having to explicitly allocate the mutex before + * use + */ +#define g_static_mutex_lock(mutex) \ +    g_mutex_lock (g_static_mutex_get_mutex (mutex)) +#define g_static_mutex_trylock(mutex) \ +    g_mutex_trylock (g_static_mutex_get_mutex (mutex)) +#define g_static_mutex_unlock(mutex) \ +    g_mutex_unlock (g_static_mutex_get_mutex (mutex)) +void g_static_mutex_init (GStaticMutex *mutex); +void g_static_mutex_free (GStaticMutex *mutex); + +struct _GStaticPrivate +{ +  /*< private >*/ +  guint index; +}; +#define G_STATIC_PRIVATE_INIT { 0 } +void     g_static_private_init           (GStaticPrivate   *private_key); +gpointer g_static_private_get            (GStaticPrivate   *private_key); +void     g_static_private_set            (GStaticPrivate   *private_key, +					  gpointer          data, +					  GDestroyNotify    notify); +void     g_static_private_free           (GStaticPrivate   *private_key); + +typedef struct _GStaticRecMutex GStaticRecMutex; +struct _GStaticRecMutex +{ +  /*< private >*/ +  GStaticMutex mutex; +  guint depth; +  GSystemThread owner; +}; + +#define G_STATIC_REC_MUTEX_INIT { G_STATIC_MUTEX_INIT } +void     g_static_rec_mutex_init        (GStaticRecMutex *mutex); +void     g_static_rec_mutex_lock        (GStaticRecMutex *mutex); +gboolean g_static_rec_mutex_trylock     (GStaticRecMutex *mutex); +void     g_static_rec_mutex_unlock      (GStaticRecMutex *mutex); +void     g_static_rec_mutex_lock_full   (GStaticRecMutex *mutex, +                                         guint            depth); +guint    g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex); +void     g_static_rec_mutex_free        (GStaticRecMutex *mutex); + +typedef struct _GStaticRWLock GStaticRWLock; +struct _GStaticRWLock +{ +  /*< private >*/ +  GStaticMutex mutex; +  GCond *read_cond; +  GCond *write_cond; +  guint read_counter; +  gboolean have_writer; +  guint want_to_read; +  guint want_to_write; +}; + +#define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, 0, 0 } + +void      g_static_rw_lock_init           (GStaticRWLock* lock); +void      g_static_rw_lock_reader_lock    (GStaticRWLock* lock); +gboolean  g_static_rw_lock_reader_trylock (GStaticRWLock* lock); +void      g_static_rw_lock_reader_unlock  (GStaticRWLock* lock); +void      g_static_rw_lock_writer_lock    (GStaticRWLock* lock); +gboolean  g_static_rw_lock_writer_trylock (GStaticRWLock* lock); +void      g_static_rw_lock_writer_unlock  (GStaticRWLock* lock); +void      g_static_rw_lock_free           (GStaticRWLock* lock); + +void	  g_thread_foreach         	  (GFunc    	  thread_func, +					   gpointer 	  user_data); + +typedef enum +{ +  G_ONCE_STATUS_NOTCALLED, +  G_ONCE_STATUS_PROGRESS, +  G_ONCE_STATUS_READY   +} GOnceStatus; + +typedef struct _GOnce GOnce; +struct _GOnce +{ +  volatile GOnceStatus status; +  volatile gpointer retval; +}; + +#define G_ONCE_INIT { G_ONCE_STATUS_NOTCALLED, NULL } + +gpointer g_once_impl (GOnce *once, GThreadFunc func, gpointer arg); + +#ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED +# define g_once(once, func, arg) g_once_impl ((once), (func), (arg)) +#else /* !G_ATOMIC_OP_MEMORY_BARRIER_NEEDED*/ +# define g_once(once, func, arg) \ +  (((once)->status == G_ONCE_STATUS_READY) ? \ +   (once)->retval : \ +   g_once_impl ((once), (func), (arg))) +#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ + +/* initialize-once guards, keyed by value_location */ +G_INLINE_FUNC gboolean  g_once_init_enter       (volatile gsize *value_location); +gboolean                g_once_init_enter_impl  (volatile gsize *value_location); +void                    g_once_init_leave       (volatile gsize *value_location, +                                                 gsize           initialization_value); +#if defined (G_CAN_INLINE) || defined (__G_THREAD_C__) +G_INLINE_FUNC gboolean +g_once_init_enter (volatile gsize *value_location) +{ +  if G_LIKELY ((gpointer) g_atomic_pointer_get (value_location) != NULL) +    return FALSE; +  else +    return g_once_init_enter_impl (value_location); +} +#endif /* G_CAN_INLINE || __G_THREAD_C__ */ + +/* these are some convenience macros that expand to nothing if GLib + * was configured with --disable-threads. for using StaticMutexes, + * you define them with G_LOCK_DEFINE_STATIC (name) or G_LOCK_DEFINE (name) + * if you need to export the mutex. With G_LOCK_EXTERN (name) you can + * declare such an globally defined lock. name is a unique identifier + * for the protected varibale or code portion. locking, testing and + * unlocking of such mutexes can be done with G_LOCK(), G_UNLOCK() and + * G_TRYLOCK() respectively. + */ +extern void glib_dummy_decl (void); +#define G_LOCK_NAME(name)               g__ ## name ## _lock +#ifdef  G_THREADS_ENABLED +#  define G_LOCK_DEFINE_STATIC(name)    static G_LOCK_DEFINE (name) +#  define G_LOCK_DEFINE(name)           \ +    GStaticMutex G_LOCK_NAME (name) = G_STATIC_MUTEX_INIT +#  define G_LOCK_EXTERN(name)           extern GStaticMutex G_LOCK_NAME (name) + +#  ifdef G_DEBUG_LOCKS +#    define G_LOCK(name)                G_STMT_START{             \ +        g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,                   \ +               "file %s: line %d (%s): locking: %s ",             \ +               __FILE__,        __LINE__, G_STRFUNC,              \ +               #name);                                            \ +        g_static_mutex_lock (&G_LOCK_NAME (name));                \ +     }G_STMT_END +#    define G_UNLOCK(name)              G_STMT_START{             \ +        g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,                   \ +               "file %s: line %d (%s): unlocking: %s ",           \ +               __FILE__,        __LINE__, G_STRFUNC,              \ +               #name);                                            \ +       g_static_mutex_unlock (&G_LOCK_NAME (name));               \ +     }G_STMT_END +#    define G_TRYLOCK(name)                                       \ +        (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,                  \ +               "file %s: line %d (%s): try locking: %s ",         \ +               __FILE__,        __LINE__, G_STRFUNC,              \ +               #name), g_static_mutex_trylock (&G_LOCK_NAME (name))) +#  else  /* !G_DEBUG_LOCKS */ +#    define G_LOCK(name) g_static_mutex_lock       (&G_LOCK_NAME (name)) +#    define G_UNLOCK(name) g_static_mutex_unlock   (&G_LOCK_NAME (name)) +#    define G_TRYLOCK(name) g_static_mutex_trylock (&G_LOCK_NAME (name)) +#  endif /* !G_DEBUG_LOCKS */ +#else   /* !G_THREADS_ENABLED */ +#  define G_LOCK_DEFINE_STATIC(name)    extern void glib_dummy_decl (void) +#  define G_LOCK_DEFINE(name)           extern void glib_dummy_decl (void) +#  define G_LOCK_EXTERN(name)           extern void glib_dummy_decl (void) +#  define G_LOCK(name) +#  define G_UNLOCK(name) +#  define G_TRYLOCK(name)               (TRUE) +#endif  /* !G_THREADS_ENABLED */ + +G_END_DECLS + +#endif /* __G_THREAD_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gthreadpool.h b/protocols/Sametime/src/glib/include/glib/gthreadpool.h new file mode 100644 index 0000000000..d5864241e6 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gthreadpool.h @@ -0,0 +1,114 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_THREADPOOL_H__ +#define __G_THREADPOOL_H__ + +#include <glib/gthread.h> + +G_BEGIN_DECLS + +typedef struct _GThreadPool     GThreadPool; + +/* Thread Pools + */ + +/* The real GThreadPool is bigger, so you may only create a thread + * pool with the constructor function */ +struct _GThreadPool +{ +  GFunc func; +  gpointer user_data; +  gboolean exclusive; +}; + +/* Get a thread pool with the function func, at most max_threads may + * run at a time (max_threads == -1 means no limit), exclusive == TRUE + * means, that the threads shouldn't be shared and that they will be + * prestarted (otherwise they are started as needed) user_data is the + * 2nd argument to the func */ +GThreadPool*    g_thread_pool_new             (GFunc            func, +                                               gpointer         user_data, +                                               gint             max_threads, +                                               gboolean         exclusive, +                                               GError         **error); + +/* Push new data into the thread pool. This task is assigned to a thread later + * (when the maximal number of threads is reached for that pool) or now + * (otherwise). If necessary a new thread will be started. The function + * returns immediatly */ +void            g_thread_pool_push            (GThreadPool     *pool, +                                               gpointer         data, +                                               GError         **error); + +/* Set the number of threads, which can run concurrently for that pool, -1 + * means no limit. 0 means has the effect, that the pool won't process + * requests until the limit is set higher again */ +void            g_thread_pool_set_max_threads (GThreadPool     *pool, +                                               gint             max_threads, +                                               GError         **error); +gint            g_thread_pool_get_max_threads (GThreadPool     *pool); + +/* Get the number of threads assigned to that pool. This number doesn't + * necessarily represent the number of working threads in that pool */ +guint           g_thread_pool_get_num_threads (GThreadPool     *pool); + +/* Get the number of unprocessed items in the pool */ +guint           g_thread_pool_unprocessed     (GThreadPool     *pool); + +/* Free the pool, immediate means, that all unprocessed items in the queue + * wont be processed, wait means, that the function doesn't return immediatly, + * but after all threads in the pool are ready processing items. immediate + * does however not mean, that threads are killed. */ +void            g_thread_pool_free            (GThreadPool     *pool, +                                               gboolean         immediate, +                                               gboolean         wait_); + +/* Set the maximal number of unused threads before threads will be stopped by + * GLib, -1 means no limit */ +void            g_thread_pool_set_max_unused_threads (gint      max_threads); +gint            g_thread_pool_get_max_unused_threads (void); +guint           g_thread_pool_get_num_unused_threads (void); + +/* Stop all currently unused threads, but leave the limit untouched */ +void            g_thread_pool_stop_unused_threads    (void); + +/* Set sort function for priority threading */ +void            g_thread_pool_set_sort_function      (GThreadPool      *pool, +		                                      GCompareDataFunc  func, +						      gpointer          user_data); + +/* Set maximum time a thread can be idle in the pool before it is stopped */ +void            g_thread_pool_set_max_idle_time      (guint             interval); +guint           g_thread_pool_get_max_idle_time      (void); + +G_END_DECLS + +#endif /* __G_THREADPOOL_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gtimer.h b/protocols/Sametime/src/glib/include/glib/gtimer.h new file mode 100644 index 0000000000..743eed1f90 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gtimer.h @@ -0,0 +1,65 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_TIMER_H__ +#define __G_TIMER_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +/* Timer + */ + +/* microseconds per second */ +typedef struct _GTimer		GTimer; + +#define G_USEC_PER_SEC 1000000 + +GTimer*  g_timer_new	         (void); +void	 g_timer_destroy         (GTimer      *timer); +void	 g_timer_start	         (GTimer      *timer); +void	 g_timer_stop	         (GTimer      *timer); +void	 g_timer_reset	         (GTimer      *timer); +void	 g_timer_continue        (GTimer      *timer); +gdouble  g_timer_elapsed         (GTimer      *timer, +				  gulong      *microseconds); + +void     g_usleep                (gulong       microseconds); + +void     g_time_val_add          (GTimeVal    *time_,  +                                  glong        microseconds); +gboolean g_time_val_from_iso8601 (const gchar *iso_date, +				  GTimeVal    *time_); +gchar*   g_time_val_to_iso8601   (GTimeVal    *time_) G_GNUC_MALLOC; + +G_END_DECLS + +#endif /* __G_TIMER_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gtimezone.h b/protocols/Sametime/src/glib/include/glib/gtimezone.h new file mode 100644 index 0000000000..1032a3c09c --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gtimezone.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2010 Codethink Limited + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + * + * Author: Ryan Lortie <desrt@desrt.ca> + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_TIME_ZONE_H__ +#define __G_TIME_ZONE_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +typedef struct _GTimeZone GTimeZone; + +GTimeZone *             g_time_zone_new                                 (const gchar *identifier); +GTimeZone *             g_time_zone_new_utc                             (void); +GTimeZone *             g_time_zone_new_local                           (void); + +GTimeZone *             g_time_zone_ref                                 (GTimeZone   *tz); +void                    g_time_zone_unref                               (GTimeZone   *tz); + +G_END_DECLS + +#endif /* __G_TIME_ZONE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gtree.h b/protocols/Sametime/src/glib/include/glib/gtree.h new file mode 100644 index 0000000000..db06ba3b82 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gtree.h @@ -0,0 +1,91 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_TREE_H__ +#define __G_TREE_H__ + +#include <glib/gnode.h> + +G_BEGIN_DECLS + +typedef struct _GTree  GTree; + +typedef gboolean (*GTraverseFunc) (gpointer  key, +                                   gpointer  value, +                                   gpointer  data); + +/* Balanced binary trees + */ +GTree*   g_tree_new             (GCompareFunc      key_compare_func); +GTree*   g_tree_new_with_data   (GCompareDataFunc  key_compare_func, +                                 gpointer          key_compare_data); +GTree*   g_tree_new_full        (GCompareDataFunc  key_compare_func, +                                 gpointer          key_compare_data, +                                 GDestroyNotify    key_destroy_func, +                                 GDestroyNotify    value_destroy_func); +GTree*   g_tree_ref             (GTree            *tree); +void     g_tree_unref           (GTree            *tree); +void     g_tree_destroy         (GTree            *tree); +void     g_tree_insert          (GTree            *tree, +                                 gpointer          key, +                                 gpointer          value); +void     g_tree_replace         (GTree            *tree, +                                 gpointer          key, +                                 gpointer          value); +gboolean g_tree_remove          (GTree            *tree, +                                 gconstpointer     key); +gboolean g_tree_steal           (GTree            *tree, +                                 gconstpointer     key); +gpointer g_tree_lookup          (GTree            *tree, +                                 gconstpointer     key); +gboolean g_tree_lookup_extended (GTree            *tree, +                                 gconstpointer     lookup_key, +                                 gpointer         *orig_key, +                                 gpointer         *value); +void     g_tree_foreach         (GTree            *tree, +                                 GTraverseFunc	   func, +                                 gpointer	   user_data); + +#ifndef G_DISABLE_DEPRECATED +void     g_tree_traverse        (GTree            *tree, +                                 GTraverseFunc     traverse_func, +                                 GTraverseType     traverse_type, +                                 gpointer          user_data); +#endif /* G_DISABLE_DEPRECATED */ + +gpointer g_tree_search          (GTree            *tree, +                                 GCompareFunc      search_func, +                                 gconstpointer     user_data); +gint     g_tree_height          (GTree            *tree); +gint     g_tree_nnodes          (GTree            *tree); + +G_END_DECLS + +#endif /* __G_TREE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gtypes.h b/protocols/Sametime/src/glib/include/glib/gtypes.h new file mode 100644 index 0000000000..e616f9988c --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gtypes.h @@ -0,0 +1,451 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_TYPES_H__ +#define __G_TYPES_H__ + +#include <glibconfig.h> +#include <glib/gmacros.h> + +G_BEGIN_DECLS + +/* Provide type definitions for commonly used types. + *  These are useful because a "gint8" can be adjusted + *  to be 1 byte (8 bits) on all platforms. Similarly and + *  more importantly, "gint32" can be adjusted to be + *  4 bytes (32 bits) on all platforms. + */ + +typedef char   gchar; +typedef short  gshort; +typedef long   glong; +typedef int    gint; +typedef gint   gboolean; + +typedef unsigned char   guchar; +typedef unsigned short  gushort; +typedef unsigned long   gulong; +typedef unsigned int    guint; + +typedef float   gfloat; +typedef double  gdouble; + +/* Define min and max constants for the fixed size numerical types */ +#define G_MININT8	((gint8)  0x80) +#define G_MAXINT8	((gint8)  0x7f) +#define G_MAXUINT8	((guint8) 0xff) + +#define G_MININT16	((gint16)  0x8000) +#define G_MAXINT16	((gint16)  0x7fff) +#define G_MAXUINT16	((guint16) 0xffff) + +#define G_MININT32	((gint32)  0x80000000) +#define G_MAXINT32	((gint32)  0x7fffffff) +#define G_MAXUINT32	((guint32) 0xffffffff) + +#define G_MININT64	((gint64) G_GINT64_CONSTANT(0x8000000000000000)) +#define G_MAXINT64	G_GINT64_CONSTANT(0x7fffffffffffffff) +#define G_MAXUINT64	G_GINT64_CONSTANT(0xffffffffffffffffU) + +typedef void* gpointer; +typedef const void *gconstpointer; + +typedef gint            (*GCompareFunc)         (gconstpointer  a, +                                                 gconstpointer  b); +typedef gint            (*GCompareDataFunc)     (gconstpointer  a, +                                                 gconstpointer  b, +						 gpointer       user_data); +typedef gboolean        (*GEqualFunc)           (gconstpointer  a, +                                                 gconstpointer  b); +typedef void            (*GDestroyNotify)       (gpointer       data); +typedef void            (*GFunc)                (gpointer       data, +                                                 gpointer       user_data); +typedef guint           (*GHashFunc)            (gconstpointer  key); +typedef void            (*GHFunc)               (gpointer       key, +                                                 gpointer       value, +                                                 gpointer       user_data); +typedef void            (*GFreeFunc)            (gpointer       data); + +/** + * GTranslateFunc: + * @str: the untranslated string + * @data: user data specified when installing the function, e.g. + *  in g_option_group_set_translate_func() + *  + * The type of functions which are used to translate user-visible + * strings, for <option>--help</option> output. + *  + * Returns: a translation of the string for the current locale. + *  The returned string is owned by GLib and must not be freed. + */ +typedef const gchar *   (*GTranslateFunc)       (const gchar   *str, +						 gpointer       data); + + +/* Define some mathematical constants that aren't available + * symbolically in some strict ISO C implementations. + * + * Note that the large number of digits used in these definitions + * doesn't imply that GLib or current computers in general would be + * able to handle floating point numbers with an accuracy like this. + * It's mostly an exercise in futility and future proofing. For + * extended precision floating point support, look somewhere else + * than GLib. + */ +#define G_E     2.7182818284590452353602874713526624977572470937000 +#define G_LN2   0.69314718055994530941723212145817656807550013436026 +#define G_LN10  2.3025850929940456840179914546843642076011014886288 +#define G_PI    3.1415926535897932384626433832795028841971693993751 +#define G_PI_2  1.5707963267948966192313216916397514420985846996876 +#define G_PI_4  0.78539816339744830961566084581987572104929234984378 +#define G_SQRT2 1.4142135623730950488016887242096980785696718753769 + +/* Portable endian checks and conversions + * + * glibconfig.h defines G_BYTE_ORDER which expands to one of + * the below macros. + */ +#define G_LITTLE_ENDIAN 1234 +#define G_BIG_ENDIAN    4321 +#define G_PDP_ENDIAN    3412		/* unused, need specific PDP check */	 + + +/* Basic bit swapping functions + */ +#define GUINT16_SWAP_LE_BE_CONSTANT(val)	((guint16) ( \ +    (guint16) ((guint16) (val) >> 8) |	\ +    (guint16) ((guint16) (val) << 8))) + +#define GUINT32_SWAP_LE_BE_CONSTANT(val)	((guint32) ( \ +    (((guint32) (val) & (guint32) 0x000000ffU) << 24) | \ +    (((guint32) (val) & (guint32) 0x0000ff00U) <<  8) | \ +    (((guint32) (val) & (guint32) 0x00ff0000U) >>  8) | \ +    (((guint32) (val) & (guint32) 0xff000000U) >> 24))) + +#define GUINT64_SWAP_LE_BE_CONSTANT(val)	((guint64) ( \ +      (((guint64) (val) &						\ +	(guint64) G_GINT64_CONSTANT (0x00000000000000ffU)) << 56) |	\ +      (((guint64) (val) &						\ +	(guint64) G_GINT64_CONSTANT (0x000000000000ff00U)) << 40) |	\ +      (((guint64) (val) &						\ +	(guint64) G_GINT64_CONSTANT (0x0000000000ff0000U)) << 24) |	\ +      (((guint64) (val) &						\ +	(guint64) G_GINT64_CONSTANT (0x00000000ff000000U)) <<  8) |	\ +      (((guint64) (val) &						\ +	(guint64) G_GINT64_CONSTANT (0x000000ff00000000U)) >>  8) |	\ +      (((guint64) (val) &						\ +	(guint64) G_GINT64_CONSTANT (0x0000ff0000000000U)) >> 24) |	\ +      (((guint64) (val) &						\ +	(guint64) G_GINT64_CONSTANT (0x00ff000000000000U)) >> 40) |	\ +      (((guint64) (val) &						\ +	(guint64) G_GINT64_CONSTANT (0xff00000000000000U)) >> 56))) + +/* Arch specific stuff for speed + */ +#if defined (__GNUC__) && (__GNUC__ >= 2) && defined (__OPTIMIZE__) +#  if defined (__i386__) +#    define GUINT16_SWAP_LE_BE_IA32(val) \ +       (__extension__						\ +	({ register guint16 __v, __x = ((guint16) (val));	\ +	   if (__builtin_constant_p (__x))			\ +	     __v = GUINT16_SWAP_LE_BE_CONSTANT (__x);		\ +	   else							\ +	     __asm__ ("rorw $8, %w0"				\ +		      : "=r" (__v)				\ +		      : "0" (__x)				\ +		      : "cc");					\ +	    __v; })) +#    if !defined (__i486__) && !defined (__i586__) \ +	&& !defined (__pentium__) && !defined (__i686__) \ +	&& !defined (__pentiumpro__) && !defined (__pentium4__) +#       define GUINT32_SWAP_LE_BE_IA32(val) \ +	  (__extension__					\ +	   ({ register guint32 __v, __x = ((guint32) (val));	\ +	      if (__builtin_constant_p (__x))			\ +		__v = GUINT32_SWAP_LE_BE_CONSTANT (__x);	\ +	      else						\ +		__asm__ ("rorw $8, %w0\n\t"			\ +			 "rorl $16, %0\n\t"			\ +			 "rorw $8, %w0"				\ +			 : "=r" (__v)				\ +			 : "0" (__x)				\ +			 : "cc");				\ +	      __v; })) +#    else /* 486 and higher has bswap */ +#       define GUINT32_SWAP_LE_BE_IA32(val) \ +	  (__extension__					\ +	   ({ register guint32 __v, __x = ((guint32) (val));	\ +	      if (__builtin_constant_p (__x))			\ +		__v = GUINT32_SWAP_LE_BE_CONSTANT (__x);	\ +	      else						\ +		__asm__ ("bswap %0"				\ +			 : "=r" (__v)				\ +			 : "0" (__x));				\ +	      __v; })) +#    endif /* processor specific 32-bit stuff */ +#    define GUINT64_SWAP_LE_BE_IA32(val) \ +       (__extension__							\ +	({ union { guint64 __ll;					\ +		   guint32 __l[2]; } __w, __r;				\ +	   __w.__ll = ((guint64) (val));				\ +	   if (__builtin_constant_p (__w.__ll))				\ +	     __r.__ll = GUINT64_SWAP_LE_BE_CONSTANT (__w.__ll);		\ +	   else								\ +	     {								\ +	       __r.__l[0] = GUINT32_SWAP_LE_BE (__w.__l[1]);		\ +	       __r.__l[1] = GUINT32_SWAP_LE_BE (__w.__l[0]);		\ +	     }								\ +	   __r.__ll; })) +     /* Possibly just use the constant version and let gcc figure it out? */ +#    define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_IA32 (val)) +#    define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_IA32 (val)) +#    define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_IA32 (val)) +#  elif defined (__ia64__) +#    define GUINT16_SWAP_LE_BE_IA64(val) \ +       (__extension__						\ +	({ register guint16 __v, __x = ((guint16) (val));	\ +	   if (__builtin_constant_p (__x))			\ +	     __v = GUINT16_SWAP_LE_BE_CONSTANT (__x);		\ +	   else							\ +	     __asm__ __volatile__ ("shl %0 = %1, 48 ;;"		\ +				   "mux1 %0 = %0, @rev ;;"	\ +				    : "=r" (__v)		\ +				    : "r" (__x));		\ +	    __v; })) +#    define GUINT32_SWAP_LE_BE_IA64(val) \ +       (__extension__						\ +	 ({ register guint32 __v, __x = ((guint32) (val));	\ +	    if (__builtin_constant_p (__x))			\ +	      __v = GUINT32_SWAP_LE_BE_CONSTANT (__x);		\ +	    else						\ +	     __asm__ __volatile__ ("shl %0 = %1, 32 ;;"		\ +				   "mux1 %0 = %0, @rev ;;"	\ +				    : "=r" (__v)		\ +				    : "r" (__x));		\ +	    __v; })) +#    define GUINT64_SWAP_LE_BE_IA64(val) \ +       (__extension__						\ +	({ register guint64 __v, __x = ((guint64) (val));	\ +	   if (__builtin_constant_p (__x))			\ +	     __v = GUINT64_SWAP_LE_BE_CONSTANT (__x);		\ +	   else							\ +	     __asm__ __volatile__ ("mux1 %0 = %1, @rev ;;"	\ +				   : "=r" (__v)			\ +				   : "r" (__x));		\ +	   __v; })) +#    define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_IA64 (val)) +#    define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_IA64 (val)) +#    define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_IA64 (val)) +#  elif defined (__x86_64__) +#    define GUINT32_SWAP_LE_BE_X86_64(val) \ +       (__extension__						\ +	 ({ register guint32 __v, __x = ((guint32) (val));	\ +	    if (__builtin_constant_p (__x))			\ +	      __v = GUINT32_SWAP_LE_BE_CONSTANT (__x);		\ +	    else						\ +	     __asm__ ("bswapl %0"				\ +		      : "=r" (__v)				\ +		      : "0" (__x));				\ +	    __v; })) +#    define GUINT64_SWAP_LE_BE_X86_64(val) \ +       (__extension__						\ +	({ register guint64 __v, __x = ((guint64) (val));	\ +	   if (__builtin_constant_p (__x))			\ +	     __v = GUINT64_SWAP_LE_BE_CONSTANT (__x);		\ +	   else							\ +	     __asm__ ("bswapq %0"				\ +		      : "=r" (__v)				\ +		      : "0" (__x));				\ +	   __v; })) +     /* gcc seems to figure out optimal code for this on its own */ +#    define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val)) +#    define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_X86_64 (val)) +#    define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_X86_64 (val)) +#  else /* generic gcc */ +#    define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val)) +#    define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val)) +#    define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_CONSTANT (val)) +#  endif +#else /* generic */ +#  define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val)) +#  define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val)) +#  define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_CONSTANT (val)) +#endif /* generic */ + +#define GUINT16_SWAP_LE_PDP(val)	((guint16) (val)) +#define GUINT16_SWAP_BE_PDP(val)	(GUINT16_SWAP_LE_BE (val)) +#define GUINT32_SWAP_LE_PDP(val)	((guint32) ( \ +    (((guint32) (val) & (guint32) 0x0000ffffU) << 16) | \ +    (((guint32) (val) & (guint32) 0xffff0000U) >> 16))) +#define GUINT32_SWAP_BE_PDP(val)	((guint32) ( \ +    (((guint32) (val) & (guint32) 0x00ff00ffU) << 8) | \ +    (((guint32) (val) & (guint32) 0xff00ff00U) >> 8))) + +/* The G*_TO_?E() macros are defined in glibconfig.h. + * The transformation is symmetric, so the FROM just maps to the TO. + */ +#define GINT16_FROM_LE(val)	(GINT16_TO_LE (val)) +#define GUINT16_FROM_LE(val)	(GUINT16_TO_LE (val)) +#define GINT16_FROM_BE(val)	(GINT16_TO_BE (val)) +#define GUINT16_FROM_BE(val)	(GUINT16_TO_BE (val)) +#define GINT32_FROM_LE(val)	(GINT32_TO_LE (val)) +#define GUINT32_FROM_LE(val)	(GUINT32_TO_LE (val)) +#define GINT32_FROM_BE(val)	(GINT32_TO_BE (val)) +#define GUINT32_FROM_BE(val)	(GUINT32_TO_BE (val)) + +#define GINT64_FROM_LE(val)	(GINT64_TO_LE (val)) +#define GUINT64_FROM_LE(val)	(GUINT64_TO_LE (val)) +#define GINT64_FROM_BE(val)	(GINT64_TO_BE (val)) +#define GUINT64_FROM_BE(val)	(GUINT64_TO_BE (val)) + +#define GLONG_FROM_LE(val)	(GLONG_TO_LE (val)) +#define GULONG_FROM_LE(val)	(GULONG_TO_LE (val)) +#define GLONG_FROM_BE(val)	(GLONG_TO_BE (val)) +#define GULONG_FROM_BE(val)	(GULONG_TO_BE (val)) + +#define GINT_FROM_LE(val)	(GINT_TO_LE (val)) +#define GUINT_FROM_LE(val)	(GUINT_TO_LE (val)) +#define GINT_FROM_BE(val)	(GINT_TO_BE (val)) +#define GUINT_FROM_BE(val)	(GUINT_TO_BE (val)) + +#define GSIZE_FROM_LE(val)	(GSIZE_TO_LE (val)) +#define GSSIZE_FROM_LE(val)	(GSSIZE_TO_LE (val)) +#define GSIZE_FROM_BE(val)	(GSIZE_TO_BE (val)) +#define GSSIZE_FROM_BE(val)	(GSSIZE_TO_BE (val)) + + +/* Portable versions of host-network order stuff + */ +#define g_ntohl(val) (GUINT32_FROM_BE (val)) +#define g_ntohs(val) (GUINT16_FROM_BE (val)) +#define g_htonl(val) (GUINT32_TO_BE (val)) +#define g_htons(val) (GUINT16_TO_BE (val)) + +/* IEEE Standard 754 Single Precision Storage Format (gfloat): + * + *        31 30           23 22            0 + * +--------+---------------+---------------+ + * | s 1bit | e[30:23] 8bit | f[22:0] 23bit | + * +--------+---------------+---------------+ + * B0------------------->B1------->B2-->B3--> + * + * IEEE Standard 754 Double Precision Storage Format (gdouble): + * + *        63 62            52 51            32   31            0 + * +--------+----------------+----------------+ +---------------+ + * | s 1bit | e[62:52] 11bit | f[51:32] 20bit | | f[31:0] 32bit | + * +--------+----------------+----------------+ +---------------+ + * B0--------------->B1---------->B2--->B3---->  B4->B5->B6->B7-> + */ +/* subtract from biased_exponent to form base2 exponent (normal numbers) */ +typedef union  _GDoubleIEEE754	GDoubleIEEE754; +typedef union  _GFloatIEEE754	GFloatIEEE754; +#define G_IEEE754_FLOAT_BIAS	(127) +#define G_IEEE754_DOUBLE_BIAS	(1023) +/* multiply with base2 exponent to get base10 exponent (normal numbers) */ +#define G_LOG_2_BASE_10		(0.30102999566398119521) +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +union _GFloatIEEE754 +{ +  gfloat v_float; +  struct { +    guint mantissa : 23; +    guint biased_exponent : 8; +    guint sign : 1; +  } mpn; +}; +union _GDoubleIEEE754 +{ +  gdouble v_double; +  struct { +    guint mantissa_low : 32; +    guint mantissa_high : 20; +    guint biased_exponent : 11; +    guint sign : 1; +  } mpn; +}; +#elif G_BYTE_ORDER == G_BIG_ENDIAN +union _GFloatIEEE754 +{ +  gfloat v_float; +  struct { +    guint sign : 1; +    guint biased_exponent : 8; +    guint mantissa : 23; +  } mpn; +}; +union _GDoubleIEEE754 +{ +  gdouble v_double; +  struct { +    guint sign : 1; +    guint biased_exponent : 11; +    guint mantissa_high : 20; +    guint mantissa_low : 32; +  } mpn; +}; +#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */ +#error unknown ENDIAN type +#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */ + +typedef struct _GTimeVal                GTimeVal; + +struct _GTimeVal +{ +  glong tv_sec; +  glong tv_usec; +}; + +G_END_DECLS + +/* We prefix variable declarations so they can + * properly get exported in Windows DLLs. + */ +#ifndef GLIB_VAR +#  ifdef G_PLATFORM_WIN32 +#    ifdef GLIB_STATIC_COMPILATION +#      define GLIB_VAR extern +#    else /* !GLIB_STATIC_COMPILATION */ +#      ifdef GLIB_COMPILATION +#        ifdef DLL_EXPORT +#          define GLIB_VAR __declspec(dllexport) +#        else /* !DLL_EXPORT */ +#          define GLIB_VAR extern +#        endif /* !DLL_EXPORT */ +#      else /* !GLIB_COMPILATION */ +#        define GLIB_VAR extern __declspec(dllimport) +#      endif /* !GLIB_COMPILATION */ +#    endif /* !GLIB_STATIC_COMPILATION */ +#  else /* !G_PLATFORM_WIN32 */ +#    define GLIB_VAR extern +#  endif /* !G_PLATFORM_WIN32 */ +#endif /* GLIB_VAR */ + +#endif /* __G_TYPES_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gunicode.h b/protocols/Sametime/src/glib/include/glib/gunicode.h new file mode 100644 index 0000000000..4ca7bd3017 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gunicode.h @@ -0,0 +1,421 @@ +/* gunicode.h - Unicode manipulation functions + * + *  Copyright (C) 1999, 2000 Tom Tromey + *  Copyright 2000, 2005 Red Hat, Inc. + * + * The Gnome Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Gnome Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the Gnome Library; see the file COPYING.LIB.  If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + *   Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_UNICODE_H__ +#define __G_UNICODE_H__ + +#include <glib/gerror.h> +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +typedef guint32 gunichar; +typedef guint16 gunichar2; + +/* These are the possible character classifications. + * See http://www.unicode.org/Public/UNIDATA/UCD.html#General_Category_Values + */ +typedef enum +{ +  G_UNICODE_CONTROL, +  G_UNICODE_FORMAT, +  G_UNICODE_UNASSIGNED, +  G_UNICODE_PRIVATE_USE, +  G_UNICODE_SURROGATE, +  G_UNICODE_LOWERCASE_LETTER, +  G_UNICODE_MODIFIER_LETTER, +  G_UNICODE_OTHER_LETTER, +  G_UNICODE_TITLECASE_LETTER, +  G_UNICODE_UPPERCASE_LETTER, +  G_UNICODE_COMBINING_MARK, +  G_UNICODE_ENCLOSING_MARK, +  G_UNICODE_NON_SPACING_MARK, +  G_UNICODE_DECIMAL_NUMBER, +  G_UNICODE_LETTER_NUMBER, +  G_UNICODE_OTHER_NUMBER, +  G_UNICODE_CONNECT_PUNCTUATION, +  G_UNICODE_DASH_PUNCTUATION, +  G_UNICODE_CLOSE_PUNCTUATION, +  G_UNICODE_FINAL_PUNCTUATION, +  G_UNICODE_INITIAL_PUNCTUATION, +  G_UNICODE_OTHER_PUNCTUATION, +  G_UNICODE_OPEN_PUNCTUATION, +  G_UNICODE_CURRENCY_SYMBOL, +  G_UNICODE_MODIFIER_SYMBOL, +  G_UNICODE_MATH_SYMBOL, +  G_UNICODE_OTHER_SYMBOL, +  G_UNICODE_LINE_SEPARATOR, +  G_UNICODE_PARAGRAPH_SEPARATOR, +  G_UNICODE_SPACE_SEPARATOR +} GUnicodeType; + +/* These are the possible line break classifications. + * Note that new types may be added in the future. + * Implementations may regard unknown values like G_UNICODE_BREAK_UNKNOWN + * See http://www.unicode.org/unicode/reports/tr14/ + */ +typedef enum +{ +  G_UNICODE_BREAK_MANDATORY, +  G_UNICODE_BREAK_CARRIAGE_RETURN, +  G_UNICODE_BREAK_LINE_FEED, +  G_UNICODE_BREAK_COMBINING_MARK, +  G_UNICODE_BREAK_SURROGATE, +  G_UNICODE_BREAK_ZERO_WIDTH_SPACE, +  G_UNICODE_BREAK_INSEPARABLE, +  G_UNICODE_BREAK_NON_BREAKING_GLUE, +  G_UNICODE_BREAK_CONTINGENT, +  G_UNICODE_BREAK_SPACE, +  G_UNICODE_BREAK_AFTER, +  G_UNICODE_BREAK_BEFORE, +  G_UNICODE_BREAK_BEFORE_AND_AFTER, +  G_UNICODE_BREAK_HYPHEN, +  G_UNICODE_BREAK_NON_STARTER, +  G_UNICODE_BREAK_OPEN_PUNCTUATION, +  G_UNICODE_BREAK_CLOSE_PUNCTUATION, +  G_UNICODE_BREAK_QUOTATION, +  G_UNICODE_BREAK_EXCLAMATION, +  G_UNICODE_BREAK_IDEOGRAPHIC, +  G_UNICODE_BREAK_NUMERIC, +  G_UNICODE_BREAK_INFIX_SEPARATOR, +  G_UNICODE_BREAK_SYMBOL, +  G_UNICODE_BREAK_ALPHABETIC, +  G_UNICODE_BREAK_PREFIX, +  G_UNICODE_BREAK_POSTFIX, +  G_UNICODE_BREAK_COMPLEX_CONTEXT, +  G_UNICODE_BREAK_AMBIGUOUS, +  G_UNICODE_BREAK_UNKNOWN, +  G_UNICODE_BREAK_NEXT_LINE, +  G_UNICODE_BREAK_WORD_JOINER, +  G_UNICODE_BREAK_HANGUL_L_JAMO, +  G_UNICODE_BREAK_HANGUL_V_JAMO, +  G_UNICODE_BREAK_HANGUL_T_JAMO, +  G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, +  G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE +} GUnicodeBreakType; + +typedef enum  +{                         /* ISO 15924 code */ +  G_UNICODE_SCRIPT_INVALID_CODE = -1, +  G_UNICODE_SCRIPT_COMMON       = 0,   /* Zyyy */ +  G_UNICODE_SCRIPT_INHERITED,          /* Qaai */ +  G_UNICODE_SCRIPT_ARABIC,             /* Arab */ +  G_UNICODE_SCRIPT_ARMENIAN,           /* Armn */ +  G_UNICODE_SCRIPT_BENGALI,            /* Beng */ +  G_UNICODE_SCRIPT_BOPOMOFO,           /* Bopo */ +  G_UNICODE_SCRIPT_CHEROKEE,           /* Cher */ +  G_UNICODE_SCRIPT_COPTIC,             /* Qaac */ +  G_UNICODE_SCRIPT_CYRILLIC,           /* Cyrl (Cyrs) */ +  G_UNICODE_SCRIPT_DESERET,            /* Dsrt */ +  G_UNICODE_SCRIPT_DEVANAGARI,         /* Deva */ +  G_UNICODE_SCRIPT_ETHIOPIC,           /* Ethi */ +  G_UNICODE_SCRIPT_GEORGIAN,           /* Geor (Geon, Geoa) */ +  G_UNICODE_SCRIPT_GOTHIC,             /* Goth */ +  G_UNICODE_SCRIPT_GREEK,              /* Grek */ +  G_UNICODE_SCRIPT_GUJARATI,           /* Gujr */ +  G_UNICODE_SCRIPT_GURMUKHI,           /* Guru */ +  G_UNICODE_SCRIPT_HAN,                /* Hani */ +  G_UNICODE_SCRIPT_HANGUL,             /* Hang */ +  G_UNICODE_SCRIPT_HEBREW,             /* Hebr */ +  G_UNICODE_SCRIPT_HIRAGANA,           /* Hira */ +  G_UNICODE_SCRIPT_KANNADA,            /* Knda */ +  G_UNICODE_SCRIPT_KATAKANA,           /* Kana */ +  G_UNICODE_SCRIPT_KHMER,              /* Khmr */ +  G_UNICODE_SCRIPT_LAO,                /* Laoo */ +  G_UNICODE_SCRIPT_LATIN,              /* Latn (Latf, Latg) */ +  G_UNICODE_SCRIPT_MALAYALAM,          /* Mlym */ +  G_UNICODE_SCRIPT_MONGOLIAN,          /* Mong */ +  G_UNICODE_SCRIPT_MYANMAR,            /* Mymr */ +  G_UNICODE_SCRIPT_OGHAM,              /* Ogam */ +  G_UNICODE_SCRIPT_OLD_ITALIC,         /* Ital */ +  G_UNICODE_SCRIPT_ORIYA,              /* Orya */ +  G_UNICODE_SCRIPT_RUNIC,              /* Runr */ +  G_UNICODE_SCRIPT_SINHALA,            /* Sinh */ +  G_UNICODE_SCRIPT_SYRIAC,             /* Syrc (Syrj, Syrn, Syre) */ +  G_UNICODE_SCRIPT_TAMIL,              /* Taml */ +  G_UNICODE_SCRIPT_TELUGU,             /* Telu */ +  G_UNICODE_SCRIPT_THAANA,             /* Thaa */ +  G_UNICODE_SCRIPT_THAI,               /* Thai */ +  G_UNICODE_SCRIPT_TIBETAN,            /* Tibt */ +  G_UNICODE_SCRIPT_CANADIAN_ABORIGINAL, /* Cans */ +  G_UNICODE_SCRIPT_YI,                 /* Yiii */ +  G_UNICODE_SCRIPT_TAGALOG,            /* Tglg */ +  G_UNICODE_SCRIPT_HANUNOO,            /* Hano */ +  G_UNICODE_SCRIPT_BUHID,              /* Buhd */ +  G_UNICODE_SCRIPT_TAGBANWA,           /* Tagb */ + +  /* Unicode-4.0 additions */ +  G_UNICODE_SCRIPT_BRAILLE,            /* Brai */ +  G_UNICODE_SCRIPT_CYPRIOT,            /* Cprt */ +  G_UNICODE_SCRIPT_LIMBU,              /* Limb */ +  G_UNICODE_SCRIPT_OSMANYA,            /* Osma */ +  G_UNICODE_SCRIPT_SHAVIAN,            /* Shaw */ +  G_UNICODE_SCRIPT_LINEAR_B,           /* Linb */ +  G_UNICODE_SCRIPT_TAI_LE,             /* Tale */ +  G_UNICODE_SCRIPT_UGARITIC,           /* Ugar */ +       +  /* Unicode-4.1 additions */ +  G_UNICODE_SCRIPT_NEW_TAI_LUE,        /* Talu */ +  G_UNICODE_SCRIPT_BUGINESE,           /* Bugi */ +  G_UNICODE_SCRIPT_GLAGOLITIC,         /* Glag */ +  G_UNICODE_SCRIPT_TIFINAGH,           /* Tfng */ +  G_UNICODE_SCRIPT_SYLOTI_NAGRI,       /* Sylo */ +  G_UNICODE_SCRIPT_OLD_PERSIAN,        /* Xpeo */ +  G_UNICODE_SCRIPT_KHAROSHTHI,         /* Khar */ + +  /* Unicode-5.0 additions */ +  G_UNICODE_SCRIPT_UNKNOWN,            /* Zzzz */ +  G_UNICODE_SCRIPT_BALINESE,           /* Bali */ +  G_UNICODE_SCRIPT_CUNEIFORM,          /* Xsux */ +  G_UNICODE_SCRIPT_PHOENICIAN,         /* Phnx */ +  G_UNICODE_SCRIPT_PHAGS_PA,           /* Phag */ +  G_UNICODE_SCRIPT_NKO,                /* Nkoo */ + +  /* Unicode-5.1 additions */ +  G_UNICODE_SCRIPT_KAYAH_LI,           /* Kali */ +  G_UNICODE_SCRIPT_LEPCHA,             /* Lepc */ +  G_UNICODE_SCRIPT_REJANG,             /* Rjng */ +  G_UNICODE_SCRIPT_SUNDANESE,          /* Sund */ +  G_UNICODE_SCRIPT_SAURASHTRA,         /* Saur */ +  G_UNICODE_SCRIPT_CHAM,               /* Cham */ +  G_UNICODE_SCRIPT_OL_CHIKI,           /* Olck */ +  G_UNICODE_SCRIPT_VAI,                /* Vaii */ +  G_UNICODE_SCRIPT_CARIAN,             /* Cari */ +  G_UNICODE_SCRIPT_LYCIAN,             /* Lyci */ +  G_UNICODE_SCRIPT_LYDIAN,             /* Lydi */ + +  /* Unicode-5.2 additions */ +  G_UNICODE_SCRIPT_AVESTAN,                /* Avestan */ +  G_UNICODE_SCRIPT_BAMUM,                  /* Bamum */ +  G_UNICODE_SCRIPT_EGYPTIAN_HIEROGLYPHS,   /* Egyptian Hieroglyphs */ +  G_UNICODE_SCRIPT_IMPERIAL_ARAMAIC,       /* Imperial Aramaic */ +  G_UNICODE_SCRIPT_INSCRIPTIONAL_PAHLAVI,  /* Inscriptional Pahlavi */ +  G_UNICODE_SCRIPT_INSCRIPTIONAL_PARTHIAN, /* Inscriptional Parthian */ +  G_UNICODE_SCRIPT_JAVANESE,               /* Javanese */ +  G_UNICODE_SCRIPT_KAITHI,                 /* Kaithi */ +  G_UNICODE_SCRIPT_LISU,                   /* Lisu */ +  G_UNICODE_SCRIPT_MEETEI_MAYEK,           /* Meetei Mayek */ +  G_UNICODE_SCRIPT_OLD_SOUTH_ARABIAN,      /* Old South Arabian */ +  G_UNICODE_SCRIPT_OLD_TURKISH,            /* Old Turkish */ +  G_UNICODE_SCRIPT_SAMARITAN,              /* Samaritan */ +  G_UNICODE_SCRIPT_TAI_THAM,               /* Tai Tham */ +  G_UNICODE_SCRIPT_TAI_VIET                /* Tai Viet */ +} GUnicodeScript; + +/* Returns TRUE if current locale uses UTF-8 charset.  If CHARSET is + * not null, sets *CHARSET to the name of the current locale's + * charset.  This value is statically allocated, and should be copied + * in case the locale's charset will be changed later using setlocale() + * or in some other way. + */ +gboolean g_get_charset (G_CONST_RETURN char **charset); + +/* These are all analogs of the <ctype.h> functions. + */ +gboolean g_unichar_isalnum   (gunichar c) G_GNUC_CONST; +gboolean g_unichar_isalpha   (gunichar c) G_GNUC_CONST; +gboolean g_unichar_iscntrl   (gunichar c) G_GNUC_CONST; +gboolean g_unichar_isdigit   (gunichar c) G_GNUC_CONST; +gboolean g_unichar_isgraph   (gunichar c) G_GNUC_CONST; +gboolean g_unichar_islower   (gunichar c) G_GNUC_CONST; +gboolean g_unichar_isprint   (gunichar c) G_GNUC_CONST; +gboolean g_unichar_ispunct   (gunichar c) G_GNUC_CONST; +gboolean g_unichar_isspace   (gunichar c) G_GNUC_CONST; +gboolean g_unichar_isupper   (gunichar c) G_GNUC_CONST; +gboolean g_unichar_isxdigit  (gunichar c) G_GNUC_CONST; +gboolean g_unichar_istitle   (gunichar c) G_GNUC_CONST; +gboolean g_unichar_isdefined (gunichar c) G_GNUC_CONST; +gboolean g_unichar_iswide    (gunichar c) G_GNUC_CONST; +gboolean g_unichar_iswide_cjk(gunichar c) G_GNUC_CONST; +gboolean g_unichar_iszerowidth(gunichar c) G_GNUC_CONST; +gboolean g_unichar_ismark    (gunichar c) G_GNUC_CONST; + +/* More <ctype.h> functions.  These convert between the three cases. + * See the Unicode book to understand title case.  */ +gunichar g_unichar_toupper (gunichar c) G_GNUC_CONST; +gunichar g_unichar_tolower (gunichar c) G_GNUC_CONST; +gunichar g_unichar_totitle (gunichar c) G_GNUC_CONST; + +/* If C is a digit (according to `g_unichar_isdigit'), then return its +   numeric value.  Otherwise return -1.  */ +gint g_unichar_digit_value (gunichar c) G_GNUC_CONST; + +gint g_unichar_xdigit_value (gunichar c) G_GNUC_CONST; + +/* Return the Unicode character type of a given character.  */ +GUnicodeType g_unichar_type (gunichar c) G_GNUC_CONST; + +/* Return the line break property for a given character */ +GUnicodeBreakType g_unichar_break_type (gunichar c) G_GNUC_CONST; + +/* Returns the combining class for a given character */ +gint g_unichar_combining_class (gunichar uc) G_GNUC_CONST; + + +/* Compute canonical ordering of a string in-place.  This rearranges +   decomposed characters in the string according to their combining +   classes.  See the Unicode manual for more information.  */ +void g_unicode_canonical_ordering (gunichar *string, +				   gsize     len); + +/* Compute canonical decomposition of a character.  Returns g_malloc()d +   string of Unicode characters.  RESULT_LEN is set to the resulting +   length of the string.  */ +gunichar *g_unicode_canonical_decomposition (gunichar  ch, +					     gsize    *result_len) G_GNUC_MALLOC; + +/* Array of skip-bytes-per-initial character. + */ +GLIB_VAR const gchar * const g_utf8_skip; + +#define g_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(const guchar *)(p)]) + +gunichar g_utf8_get_char           (const gchar  *p) G_GNUC_PURE; +gunichar g_utf8_get_char_validated (const  gchar *p, +				    gssize        max_len) G_GNUC_PURE; + +gchar*   g_utf8_offset_to_pointer (const gchar *str, +                                   glong        offset) G_GNUC_PURE; +glong    g_utf8_pointer_to_offset (const gchar *str,       +				   const gchar *pos) G_GNUC_PURE; +gchar*   g_utf8_prev_char         (const gchar *p) G_GNUC_PURE; +gchar*   g_utf8_find_next_char    (const gchar *p, +				   const gchar *end) G_GNUC_PURE; +gchar*   g_utf8_find_prev_char    (const gchar *str, +				   const gchar *p) G_GNUC_PURE; + +glong g_utf8_strlen (const gchar *p,   +		     gssize       max) G_GNUC_PURE; + +/* Copies n characters from src to dest */ +gchar* g_utf8_strncpy (gchar       *dest, +		       const gchar *src, +		       gsize        n); + +/* Find the UTF-8 character corresponding to ch, in string p. These +   functions are equivalants to strchr and strrchr */ +gchar* g_utf8_strchr  (const gchar *p, +		       gssize       len, +		       gunichar     c); +gchar* g_utf8_strrchr (const gchar *p, +		       gssize       len, +		       gunichar     c); +gchar* g_utf8_strreverse (const gchar *str, +			  gssize len); + +gunichar2 *g_utf8_to_utf16     (const gchar      *str, +				glong             len,             +				glong            *items_read,      +				glong            *items_written,   +				GError          **error) G_GNUC_MALLOC; +gunichar * g_utf8_to_ucs4      (const gchar      *str, +				glong             len,             +				glong            *items_read,      +				glong            *items_written,   +				GError          **error) G_GNUC_MALLOC; +gunichar * g_utf8_to_ucs4_fast (const gchar      *str, +				glong             len,             +				glong            *items_written) G_GNUC_MALLOC;  +gunichar * g_utf16_to_ucs4     (const gunichar2  *str, +				glong             len,             +				glong            *items_read,      +				glong            *items_written,   +				GError          **error) G_GNUC_MALLOC; +gchar*     g_utf16_to_utf8     (const gunichar2  *str, +				glong             len,             +				glong            *items_read,      +				glong            *items_written,   +				GError          **error) G_GNUC_MALLOC; +gunichar2 *g_ucs4_to_utf16     (const gunichar   *str, +				glong             len,             +				glong            *items_read,      +				glong            *items_written,   +				GError          **error) G_GNUC_MALLOC; +gchar*     g_ucs4_to_utf8      (const gunichar   *str, +				glong             len,             +				glong            *items_read,      +				glong            *items_written,   +				GError          **error) G_GNUC_MALLOC; + +/* Convert a single character into UTF-8. outbuf must have at + * least 6 bytes of space. Returns the number of bytes in the + * result. + */ +gint      g_unichar_to_utf8 (gunichar    c, +			     gchar      *outbuf); + +/* Validate a UTF8 string, return TRUE if valid, put pointer to + * first invalid char in **end + */ + +gboolean g_utf8_validate (const gchar  *str, +                          gssize        max_len,   +                          const gchar **end); + +/* Validate a Unicode character */ +gboolean g_unichar_validate (gunichar ch) G_GNUC_CONST; + +gchar *g_utf8_strup   (const gchar *str, +		       gssize       len) G_GNUC_MALLOC; +gchar *g_utf8_strdown (const gchar *str, +		       gssize       len) G_GNUC_MALLOC; +gchar *g_utf8_casefold (const gchar *str, +			gssize       len) G_GNUC_MALLOC; + +typedef enum { +  G_NORMALIZE_DEFAULT, +  G_NORMALIZE_NFD = G_NORMALIZE_DEFAULT, +  G_NORMALIZE_DEFAULT_COMPOSE, +  G_NORMALIZE_NFC = G_NORMALIZE_DEFAULT_COMPOSE, +  G_NORMALIZE_ALL, +  G_NORMALIZE_NFKD = G_NORMALIZE_ALL, +  G_NORMALIZE_ALL_COMPOSE, +  G_NORMALIZE_NFKC = G_NORMALIZE_ALL_COMPOSE +} GNormalizeMode; + +gchar *g_utf8_normalize (const gchar   *str, +			 gssize         len, +			 GNormalizeMode mode) G_GNUC_MALLOC; + +gint   g_utf8_collate     (const gchar *str1, +			   const gchar *str2) G_GNUC_PURE; +gchar *g_utf8_collate_key (const gchar *str, +			   gssize       len) G_GNUC_MALLOC; +gchar *g_utf8_collate_key_for_filename (const gchar *str, +			                gssize       len) G_GNUC_MALLOC; + +gboolean g_unichar_get_mirror_char (gunichar ch, +                                    gunichar *mirrored_ch); + +GUnicodeScript g_unichar_get_script (gunichar ch) G_GNUC_CONST; + + +/* private */ + +gchar *_g_utf8_make_valid (const gchar *name); + +G_END_DECLS + +#endif /* __G_UNICODE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gurifuncs.h b/protocols/Sametime/src/glib/include/glib/gurifuncs.h new file mode 100644 index 0000000000..bbc8f8800a --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gurifuncs.h @@ -0,0 +1,81 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson <alexl@redhat.com> + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_URI_FUNCS_H__ +#define __G_URI_FUNCS_H__ + +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +/** + * G_URI_RESERVED_CHARS_GENERIC_DELIMITERS: + *  + * Generic delimiters characters as defined in RFC 3986. Includes ":/?#[]@". + **/ +#define G_URI_RESERVED_CHARS_GENERIC_DELIMITERS ":/?#[]@" + +/** + * G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS + *  + * Subcomponent delimiter characters as defined in RFC 3986. Includes "!$&'()*+,;=". + **/ +#define G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS "!$&'()*+,;=" + +/** + * G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT: + *  + * Allowed characters in path elements. Includes "!$&'()*+,;=:@". + **/ +#define G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS ":@" + +/** + * G_URI_RESERVED_CHARS_ALLOWED_IN_PATH: + *  + * Allowed characters in a path. Includes "!$&'()*+,;=:@/". + **/ +#define G_URI_RESERVED_CHARS_ALLOWED_IN_PATH G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT "/" + +/** + * G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO: + *  + * Allowed characters in userinfo as defined in RFC 3986. Includes "!$&'()*+,;=:". + **/ +#define G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS ":" + +char *   g_uri_unescape_string       (const char *escaped_string, +				      const char *illegal_characters); +char *   g_uri_unescape_segment      (const char *escaped_string, +				      const char *escaped_string_end, +				      const char *illegal_characters); +char *   g_uri_parse_scheme          (const char *uri); +char *   g_uri_escape_string         (const char *unescaped, +				      const char *reserved_chars_allowed, +				      gboolean    allow_utf8); + +G_END_DECLS + +#endif /* __G_URI_FUNCS_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gutils.h b/protocols/Sametime/src/glib/include/glib/gutils.h new file mode 100644 index 0000000000..90281579c6 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gutils.h @@ -0,0 +1,490 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_UTILS_H__ +#define __G_UTILS_H__ + +#include <glib/gtypes.h> +#include <stdarg.h> + +G_BEGIN_DECLS + +#ifdef G_OS_WIN32 + +/* On Win32, the canonical directory separator is the backslash, and + * the search path separator is the semicolon. Note that also the + * (forward) slash works as directory separator. + */ +#define G_DIR_SEPARATOR '\\' +#define G_DIR_SEPARATOR_S "\\" +#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR || (c) == '/') +#define G_SEARCHPATH_SEPARATOR ';' +#define G_SEARCHPATH_SEPARATOR_S ";" + +#else  /* !G_OS_WIN32 */ + +/* Unix */ + +#define G_DIR_SEPARATOR '/' +#define G_DIR_SEPARATOR_S "/" +#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR) +#define G_SEARCHPATH_SEPARATOR ':' +#define G_SEARCHPATH_SEPARATOR_S ":" + +#endif /* !G_OS_WIN32 */ + +/* Define G_VA_COPY() to do the right thing for copying va_list variables. + * glibconfig.h may have already defined G_VA_COPY as va_copy or __va_copy. + */ +#if !defined (G_VA_COPY) +#  if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32)) +#    define G_VA_COPY(ap1, ap2)	  (*(ap1) = *(ap2)) +#  elif defined (G_VA_COPY_AS_ARRAY) +#    define G_VA_COPY(ap1, ap2)	  g_memmove ((ap1), (ap2), sizeof (va_list)) +#  else /* va_list is a pointer */ +#    define G_VA_COPY(ap1, ap2)	  ((ap1) = (ap2)) +#  endif /* va_list is a pointer */ +#endif /* !G_VA_COPY */ + +/* inlining hassle. for compilers that don't allow the `inline' keyword, + * mostly because of strict ANSI C compliance or dumbness, we try to fall + * back to either `__inline__' or `__inline'. + * G_CAN_INLINE is defined in glibconfig.h if the compiler seems to be  + * actually *capable* to do function inlining, in which case inline  + * function bodies do make sense. we also define G_INLINE_FUNC to properly  + * export the function prototypes if no inlining can be performed. + * inline function bodies have to be special cased with G_CAN_INLINE and a + * .c file specific macro to allow one compiled instance with extern linkage + * of the functions by defining G_IMPLEMENT_INLINES and the .c file macro. + */ +#if defined (G_HAVE_INLINE) && defined (__GNUC__) && defined (__STRICT_ANSI__) +#  undef inline +#  define inline __inline__ +#elif !defined (G_HAVE_INLINE) +#  undef inline +#  if defined (G_HAVE___INLINE__) +#    define inline __inline__ +#  elif defined (G_HAVE___INLINE) +#    define inline __inline +#  else /* !inline && !__inline__ && !__inline */ +#    define inline  /* don't inline, then */ +#  endif +#endif +#ifdef G_IMPLEMENT_INLINES +#  define G_INLINE_FUNC +#  undef  G_CAN_INLINE +#elif defined (__GNUC__)  +#  define G_INLINE_FUNC static __inline __attribute__ ((unused)) +#elif defined (G_CAN_INLINE)  +#  define G_INLINE_FUNC static inline +#else /* can't inline */ +#  define G_INLINE_FUNC +#endif /* !G_INLINE_FUNC */ + +/* Retrive static string info + */ +#ifdef G_OS_WIN32 +#define g_get_user_name g_get_user_name_utf8 +#define g_get_real_name g_get_real_name_utf8 +#define g_get_home_dir g_get_home_dir_utf8 +#define g_get_tmp_dir g_get_tmp_dir_utf8 +#endif + +G_CONST_RETURN gchar* g_get_user_name        (void); +G_CONST_RETURN gchar* g_get_real_name        (void); +G_CONST_RETURN gchar* g_get_home_dir         (void); +G_CONST_RETURN gchar* g_get_tmp_dir          (void); +G_CONST_RETURN gchar* g_get_host_name	     (void); +gchar*                g_get_prgname          (void); +void                  g_set_prgname          (const gchar *prgname); +G_CONST_RETURN gchar* g_get_application_name (void); +void                  g_set_application_name (const gchar *application_name); + +void    g_reload_user_special_dirs_cache     (void); +G_CONST_RETURN gchar*    g_get_user_data_dir      (void); +G_CONST_RETURN gchar*    g_get_user_config_dir    (void); +G_CONST_RETURN gchar*    g_get_user_cache_dir     (void); +G_CONST_RETURN gchar* G_CONST_RETURN * g_get_system_data_dirs   (void); + +#ifdef G_OS_WIN32 +/* This functions is not part of the public GLib API */ +G_CONST_RETURN gchar* G_CONST_RETURN * g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void)); +#endif + +#if defined (G_OS_WIN32) && defined (G_CAN_INLINE) && !defined (__cplusplus) +/* This function is not part of the public GLib API either. Just call + * g_get_system_data_dirs() in your code, never mind that that is + * actually a macro and you will in fact call this inline function. + */ +static inline G_CONST_RETURN gchar * G_CONST_RETURN * +_g_win32_get_system_data_dirs (void) +{ +  return g_win32_get_system_data_dirs_for_module ((void (*)(void)) &_g_win32_get_system_data_dirs); +} +#define g_get_system_data_dirs _g_win32_get_system_data_dirs +#endif + +G_CONST_RETURN gchar* G_CONST_RETURN * g_get_system_config_dirs (void); + +G_CONST_RETURN gchar* G_CONST_RETURN * g_get_language_names (void); + +/** + * GUserDirectory: + * @G_USER_DIRECTORY_DESKTOP: the user's Desktop directory + * @G_USER_DIRECTORY_DOCUMENTS: the user's Documents directory + * @G_USER_DIRECTORY_DOWNLOAD: the user's Downloads directory + * @G_USER_DIRECTORY_MUSIC: the user's Music directory + * @G_USER_DIRECTORY_PICTURES: the user's Pictures directory + * @G_USER_DIRECTORY_PUBLIC_SHARE: the user's shared directory + * @G_USER_DIRECTORY_TEMPLATES: the user's Templates directory + * @G_USER_DIRECTORY_VIDEOS: the user's Movies directory + * @G_USER_N_DIRECTORIES: the number of enum values + * + * These are logical ids for special directories which are defined + * depending on the platform used. You should use g_get_user_special_dir() + * to retrieve the full path associated to the logical id. + * + * The #GUserDirectory enumeration can be extended at later date. Not + * every platform has a directory for every logical id in this + * enumeration. + * + * Since: 2.14 + */ +typedef enum { +  G_USER_DIRECTORY_DESKTOP, +  G_USER_DIRECTORY_DOCUMENTS, +  G_USER_DIRECTORY_DOWNLOAD, +  G_USER_DIRECTORY_MUSIC, +  G_USER_DIRECTORY_PICTURES, +  G_USER_DIRECTORY_PUBLIC_SHARE, +  G_USER_DIRECTORY_TEMPLATES, +  G_USER_DIRECTORY_VIDEOS, + +  G_USER_N_DIRECTORIES +} GUserDirectory; + +G_CONST_RETURN gchar* g_get_user_special_dir (GUserDirectory directory); + +typedef struct _GDebugKey	GDebugKey; +struct _GDebugKey +{ +  const gchar *key; +  guint	       value; +}; + +/* Miscellaneous utility functions + */ +guint                 g_parse_debug_string (const gchar     *string, +					    const GDebugKey *keys, +					    guint            nkeys); + +gint                  g_snprintf           (gchar       *string, +					    gulong       n, +					    gchar const *format, +					    ...) G_GNUC_PRINTF (3, 4); +gint                  g_vsnprintf          (gchar       *string, +					    gulong       n, +					    gchar const *format, +					    va_list      args); + +/* Check if a file name is an absolute path */ +gboolean              g_path_is_absolute   (const gchar *file_name); + +/* In case of absolute paths, skip the root part */ +G_CONST_RETURN gchar* g_path_skip_root     (const gchar *file_name); + +#ifndef G_DISABLE_DEPRECATED + +/* These two functions are deprecated and will be removed in the next + * major release of GLib. Use g_path_get_dirname/g_path_get_basename + * instead. Whatch out! The string returned by g_path_get_basename + * must be g_freed, while the string returned by g_basename must not.*/ +G_CONST_RETURN gchar* g_basename           (const gchar *file_name); +#define g_dirname g_path_get_dirname + +#endif /* G_DISABLE_DEPRECATED */ + +#ifdef G_OS_WIN32 +#define g_get_current_dir g_get_current_dir_utf8 +#endif + +/* The returned strings are newly allocated with g_malloc() */ +gchar*                g_get_current_dir    (void); +gchar*                g_path_get_basename  (const gchar *file_name) G_GNUC_MALLOC; +gchar*                g_path_get_dirname   (const gchar *file_name) G_GNUC_MALLOC; + +/* Set the pointer at the specified location to NULL */ +void                  g_nullify_pointer    (gpointer    *nullify_location); + +/* return the environment string for the variable. The returned memory + * must not be freed. */ +#ifdef G_OS_WIN32 +#define g_getenv g_getenv_utf8 +#define g_setenv g_setenv_utf8 +#define g_unsetenv g_unsetenv_utf8 +#define g_find_program_in_path g_find_program_in_path_utf8 +#endif + +G_CONST_RETURN gchar* g_getenv             (const gchar *variable); +gboolean              g_setenv             (const gchar *variable, +					    const gchar *value, +					    gboolean     overwrite); +void                  g_unsetenv           (const gchar *variable); +gchar**               g_listenv            (void); + +/* private */ +const gchar*	     _g_getenv_nomalloc	   (const gchar	*variable, +					    gchar        buffer[1024]); + +/* we try to provide a useful equivalent for ATEXIT if it is + * not defined, but use is actually abandoned. people should + * use g_atexit() instead. + */ +typedef	void		(*GVoidFunc)		(void); +#ifndef ATEXIT +# define ATEXIT(proc)	g_ATEXIT(proc) +#else +# define G_NATIVE_ATEXIT +#endif /* ATEXIT */ +/* we use a GLib function as a replacement for ATEXIT, so + * the programmer is not required to check the return value + * (if there is any in the implementation) and doesn't encounter + * missing include files. + */ +void	g_atexit		(GVoidFunc    func); + +#ifdef G_OS_WIN32 +/* It's a bad idea to wrap atexit() on Windows. If the GLib DLL calls + * atexit(), the function will be called when the GLib DLL is detached + * from the program, which is not what the caller wants. The caller + * wants the function to be called when it *itself* exits (or is + * detached, in case the caller, too, is a DLL). + */ +#if (defined(__MINGW_H) && !defined(_STDLIB_H_)) || (defined(_MSC_VER) && !defined(_INC_STDLIB)) +int atexit (void (*)(void)); +#endif +#define g_atexit(func) atexit(func) +#endif + +/* Look for an executable in PATH, following execvp() rules */ +gchar*  g_find_program_in_path  (const gchar *program); + +/* Bit tests + */ +G_INLINE_FUNC gint	g_bit_nth_lsf (gulong  mask, +				       gint    nth_bit) G_GNUC_CONST; +G_INLINE_FUNC gint	g_bit_nth_msf (gulong  mask, +				       gint    nth_bit) G_GNUC_CONST; +G_INLINE_FUNC guint	g_bit_storage (gulong  number) G_GNUC_CONST; + +/* Trash Stacks + * elements need to be >= sizeof (gpointer) + */ +typedef struct _GTrashStack     GTrashStack; +struct _GTrashStack +{ +  GTrashStack *next; +}; + +G_INLINE_FUNC void	g_trash_stack_push	(GTrashStack **stack_p, +						 gpointer      data_p); +G_INLINE_FUNC gpointer	g_trash_stack_pop	(GTrashStack **stack_p); +G_INLINE_FUNC gpointer	g_trash_stack_peek	(GTrashStack **stack_p); +G_INLINE_FUNC guint	g_trash_stack_height	(GTrashStack **stack_p); + +/* inline function implementations + */ +#if defined (G_CAN_INLINE) || defined (__G_UTILS_C__) +G_INLINE_FUNC gint +g_bit_nth_lsf (gulong mask, +	       gint   nth_bit) +{ +  if (G_UNLIKELY (nth_bit < -1)) +    nth_bit = -1; +  while (nth_bit < ((GLIB_SIZEOF_LONG * 8) - 1)) +    { +      nth_bit++; +      if (mask & (1UL << nth_bit)) +	return nth_bit; +    } +  return -1; +} +G_INLINE_FUNC gint +g_bit_nth_msf (gulong mask, +	       gint   nth_bit) +{ +  if (nth_bit < 0 || G_UNLIKELY (nth_bit > GLIB_SIZEOF_LONG * 8)) +    nth_bit = GLIB_SIZEOF_LONG * 8; +  while (nth_bit > 0) +    { +      nth_bit--; +      if (mask & (1UL << nth_bit)) +	return nth_bit; +    } +  return -1; +} +G_INLINE_FUNC guint +g_bit_storage (gulong number) +{ +#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__) +  return G_LIKELY (number) ? +	   ((GLIB_SIZEOF_LONG * 8U - 1) ^ __builtin_clzl(number)) + 1 : 1; +#else +  register guint n_bits = 0; +   +  do +    { +      n_bits++; +      number >>= 1; +    } +  while (number); +  return n_bits; +#endif +} +G_INLINE_FUNC void +g_trash_stack_push (GTrashStack **stack_p, +		    gpointer      data_p) +{ +  GTrashStack *data = (GTrashStack *) data_p; + +  data->next = *stack_p; +  *stack_p = data; +} +G_INLINE_FUNC gpointer +g_trash_stack_pop (GTrashStack **stack_p) +{ +  GTrashStack *data; + +  data = *stack_p; +  if (data) +    { +      *stack_p = data->next; +      /* NULLify private pointer here, most platforms store NULL as +       * subsequent 0 bytes +       */ +      data->next = NULL; +    } + +  return data; +} +G_INLINE_FUNC gpointer +g_trash_stack_peek (GTrashStack **stack_p) +{ +  GTrashStack *data; + +  data = *stack_p; + +  return data; +} +G_INLINE_FUNC guint +g_trash_stack_height (GTrashStack **stack_p) +{ +  GTrashStack *data; +  guint i = 0; + +  for (data = *stack_p; data; data = data->next) +    i++; + +  return i; +} +#endif  /* G_CAN_INLINE || __G_UTILS_C__ */ + +/* Glib version. + * we prefix variable declarations so they can + * properly get exported in windows dlls. + */ +GLIB_VAR const guint glib_major_version; +GLIB_VAR const guint glib_minor_version; +GLIB_VAR const guint glib_micro_version; +GLIB_VAR const guint glib_interface_age; +GLIB_VAR const guint glib_binary_age; + +const gchar * glib_check_version (guint required_major, +                                  guint required_minor, +                                  guint required_micro); + +#define GLIB_CHECK_VERSION(major,minor,micro)    \ +    (GLIB_MAJOR_VERSION > (major) || \ +     (GLIB_MAJOR_VERSION == (major) && GLIB_MINOR_VERSION > (minor)) || \ +     (GLIB_MAJOR_VERSION == (major) && GLIB_MINOR_VERSION == (minor) && \ +      GLIB_MICRO_VERSION >= (micro))) + +G_END_DECLS + +#ifndef G_DISABLE_DEPRECATED + +/* + * This macro is deprecated. This DllMain() is too complex. It is + * recommended to write an explicit minimal DLlMain() that just saves + * the handle to the DLL and then use that handle instead, for + * instance passing it to + * g_win32_get_package_installation_directory_of_module(). + * + * On Windows, this macro defines a DllMain function that stores the + * actual DLL name that the code being compiled will be included in. + * STATIC should be empty or 'static'. DLL_NAME is the name of the + * (pointer to the) char array where the DLL name will be stored. If + * this is used, you must also include <windows.h>. If you need a more complex + * DLL entry point function, you cannot use this. + * + * On non-Windows platforms, expands to nothing. + */ + +#ifndef G_PLATFORM_WIN32 +# define G_WIN32_DLLMAIN_FOR_DLL_NAME(static, dll_name) +#else +# define G_WIN32_DLLMAIN_FOR_DLL_NAME(static, dll_name)			\ +static char *dll_name;							\ +									\ +BOOL WINAPI								\ +DllMain (HINSTANCE hinstDLL,						\ +	 DWORD     fdwReason,						\ +	 LPVOID    lpvReserved)						\ +{									\ +  wchar_t wcbfr[1000];							\ +  char *tem;								\ +  switch (fdwReason)							\ +    {									\ +    case DLL_PROCESS_ATTACH:						\ +      GetModuleFileNameW ((HMODULE) hinstDLL, wcbfr, G_N_ELEMENTS (wcbfr)); \ +      tem = g_utf16_to_utf8 (wcbfr, -1, NULL, NULL, NULL);		\ +      dll_name = g_path_get_basename (tem);				\ +      g_free (tem);							\ +      break;								\ +    }									\ +									\ +  return TRUE;								\ +} + +#endif	/* !G_DISABLE_DEPRECATED */ + +#endif /* G_PLATFORM_WIN32 */ + +#endif /* __G_UTILS_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gvariant.h b/protocols/Sametime/src/glib/include/glib/gvariant.h new file mode 100644 index 0000000000..528492b685 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gvariant.h @@ -0,0 +1,248 @@ +/* + * Copyright © 2007, 2008 Ryan Lortie + * Copyright © 2009, 2010 Codethink Limited + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Ryan Lortie <desrt@desrt.ca> + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_VARIANT_H__ +#define __G_VARIANT_H__ + +#include <glib/gvarianttype.h> +#include <glib/gstring.h> + +G_BEGIN_DECLS + +typedef struct _GVariant        GVariant; + +typedef enum +{ +  G_VARIANT_CLASS_BOOLEAN       = 'b', +  G_VARIANT_CLASS_BYTE          = 'y', +  G_VARIANT_CLASS_INT16         = 'n', +  G_VARIANT_CLASS_UINT16        = 'q', +  G_VARIANT_CLASS_INT32         = 'i', +  G_VARIANT_CLASS_UINT32        = 'u', +  G_VARIANT_CLASS_INT64         = 'x', +  G_VARIANT_CLASS_UINT64        = 't', +  G_VARIANT_CLASS_HANDLE        = 'h', +  G_VARIANT_CLASS_DOUBLE        = 'd', +  G_VARIANT_CLASS_STRING        = 's', +  G_VARIANT_CLASS_OBJECT_PATH   = 'o', +  G_VARIANT_CLASS_SIGNATURE     = 'g', +  G_VARIANT_CLASS_VARIANT       = 'v', +  G_VARIANT_CLASS_MAYBE         = 'm', +  G_VARIANT_CLASS_ARRAY         = 'a', +  G_VARIANT_CLASS_TUPLE         = '(', +  G_VARIANT_CLASS_DICT_ENTRY    = '{' +} GVariantClass; + +void                            g_variant_unref                         (GVariant             *value); +GVariant *                      g_variant_ref                           (GVariant             *value); +GVariant *                      g_variant_ref_sink                      (GVariant             *value); +gboolean                        g_variant_is_floating                   (GVariant             *value); + +const GVariantType *            g_variant_get_type                      (GVariant             *value); +const gchar *                   g_variant_get_type_string               (GVariant             *value); +gboolean                        g_variant_is_of_type                    (GVariant             *value, +                                                                         const GVariantType   *type); +gboolean                        g_variant_is_container                  (GVariant             *value); +GVariantClass                   g_variant_classify                      (GVariant             *value); +GVariant *                      g_variant_new_boolean                   (gboolean              boolean); +GVariant *                      g_variant_new_byte                      (guchar                byte); +GVariant *                      g_variant_new_int16                     (gint16                int16); +GVariant *                      g_variant_new_uint16                    (guint16               uint16); +GVariant *                      g_variant_new_int32                     (gint32                int32); +GVariant *                      g_variant_new_uint32                    (guint32               uint32); +GVariant *                      g_variant_new_int64                     (gint64                int64); +GVariant *                      g_variant_new_uint64                    (guint64               uint64); +GVariant *                      g_variant_new_handle                    (gint32                handle); +GVariant *                      g_variant_new_double                    (gdouble               floating); +GVariant *                      g_variant_new_string                    (const gchar          *string); +GVariant *                      g_variant_new_object_path               (const gchar          *object_path); +gboolean                        g_variant_is_object_path                (const gchar          *string); +GVariant *                      g_variant_new_signature                 (const gchar          *signature); +gboolean                        g_variant_is_signature                  (const gchar          *string); +GVariant *                      g_variant_new_variant                   (GVariant             *value); +GVariant *                      g_variant_new_strv                      (const gchar * const  *strv, +                                                                         gssize                length); +GVariant *                      g_variant_new_bytestring                (const gchar          *string); +GVariant *                      g_variant_new_bytestring_array          (const gchar * const  *strv, +                                                                         gssize                length); + +gboolean                        g_variant_get_boolean                   (GVariant             *value); +guchar                          g_variant_get_byte                      (GVariant             *value); +gint16                          g_variant_get_int16                     (GVariant             *value); +guint16                         g_variant_get_uint16                    (GVariant             *value); +gint32                          g_variant_get_int32                     (GVariant             *value); +guint32                         g_variant_get_uint32                    (GVariant             *value); +gint64                          g_variant_get_int64                     (GVariant             *value); +guint64                         g_variant_get_uint64                    (GVariant             *value); +gint32                          g_variant_get_handle                    (GVariant             *value); +gdouble                         g_variant_get_double                    (GVariant             *value); +GVariant *                      g_variant_get_variant                   (GVariant             *value); +const gchar *                   g_variant_get_string                    (GVariant             *value, +                                                                         gsize                *length); +gchar *                         g_variant_dup_string                    (GVariant             *value, +                                                                         gsize                *length); +const gchar **                  g_variant_get_strv                      (GVariant             *value, +                                                                         gsize                *length); +gchar **                        g_variant_dup_strv                      (GVariant             *value, +                                                                         gsize                *length); +const gchar *                   g_variant_get_bytestring                (GVariant             *value); +gchar *                         g_variant_dup_bytestring                (GVariant             *value, +                                                                         gsize                *length); +const gchar **                  g_variant_get_bytestring_array          (GVariant             *value, +                                                                         gsize                *length); +gchar **                        g_variant_dup_bytestring_array          (GVariant             *value, +                                                                         gsize                *length); + +GVariant *                      g_variant_new_maybe                     (const GVariantType   *child_type, +                                                                         GVariant             *child); +GVariant *                      g_variant_new_array                     (const GVariantType   *child_type, +                                                                         GVariant * const     *children, +                                                                         gsize                 n_children); +GVariant *                      g_variant_new_tuple                     (GVariant * const     *children, +                                                                         gsize                 n_children); +GVariant *                      g_variant_new_dict_entry                (GVariant             *key, +                                                                         GVariant             *value); + +GVariant *                      g_variant_get_maybe                     (GVariant             *value); +gsize                           g_variant_n_children                    (GVariant             *value); +void                            g_variant_get_child                     (GVariant             *value, +                                                                         gsize                 index_, +                                                                         const gchar          *format_string, +                                                                         ...); +GVariant *                      g_variant_get_child_value               (GVariant             *value, +                                                                         gsize                 index_); +gconstpointer                   g_variant_get_fixed_array               (GVariant             *value, +                                                                         gsize                *n_elements, +                                                                         gsize                 element_size); + +gsize                           g_variant_get_size                      (GVariant             *value); +gconstpointer                   g_variant_get_data                      (GVariant             *value); +void                            g_variant_store                         (GVariant             *value, +                                                                         gpointer              data); + +gchar *                         g_variant_print                         (GVariant             *value, +                                                                         gboolean              type_annotate); +GString *                       g_variant_print_string                  (GVariant             *value, +                                                                         GString              *string, +                                                                         gboolean              type_annotate); + +guint                           g_variant_hash                          (gconstpointer         value); +gboolean                        g_variant_equal                         (gconstpointer         one, +                                                                         gconstpointer         two); + +GVariant *                      g_variant_get_normal_form               (GVariant             *value); +gboolean                        g_variant_is_normal_form                (GVariant             *value); +GVariant *                      g_variant_byteswap                      (GVariant             *value); +GVariant *                      g_variant_new_from_data                 (const GVariantType   *type, +                                                                         gconstpointer         data, +                                                                         gsize                 size, +                                                                         gboolean              trusted, +                                                                         GDestroyNotify        notify, +                                                                         gpointer              user_data); + +typedef struct _GVariantIter GVariantIter; +struct _GVariantIter { +  /*< private >*/ +  gsize x[16]; +}; + +GVariantIter *                  g_variant_iter_new                      (GVariant             *value); +gsize                           g_variant_iter_init                     (GVariantIter         *iter, +                                                                         GVariant             *value); +GVariantIter *                  g_variant_iter_copy                     (GVariantIter         *iter); +gsize                           g_variant_iter_n_children               (GVariantIter         *iter); +void                            g_variant_iter_free                     (GVariantIter         *iter); +GVariant *                      g_variant_iter_next_value               (GVariantIter         *iter); +gboolean                        g_variant_iter_next                     (GVariantIter         *iter, +                                                                         const gchar          *format_string, +                                                                         ...); +gboolean                        g_variant_iter_loop                     (GVariantIter         *iter, +                                                                         const gchar          *format_string, +                                                                         ...); + + +typedef struct _GVariantBuilder GVariantBuilder; +struct _GVariantBuilder { +  /*< private >*/ +  gsize x[16]; +}; + +typedef enum +{ +  G_VARIANT_PARSE_ERROR_FAILED +} GVariantParseError; +#define G_VARIANT_PARSE_ERROR (g_variant_parser_get_error_quark ()) + +GQuark                          g_variant_parser_get_error_quark        (void); + +GVariantBuilder *               g_variant_builder_new                   (const GVariantType   *type); +void                            g_variant_builder_unref                 (GVariantBuilder      *builder); +GVariantBuilder *               g_variant_builder_ref                   (GVariantBuilder      *builder); +void                            g_variant_builder_init                  (GVariantBuilder      *builder, +                                                                         const GVariantType   *type); +GVariant *                      g_variant_builder_end                   (GVariantBuilder      *builder); +void                            g_variant_builder_clear                 (GVariantBuilder      *builder); +void                            g_variant_builder_open                  (GVariantBuilder      *builder, +                                                                         const GVariantType   *type); +void                            g_variant_builder_close                 (GVariantBuilder      *builder); +void                            g_variant_builder_add_value             (GVariantBuilder      *builder, +                                                                         GVariant             *value); +void                            g_variant_builder_add                   (GVariantBuilder      *builder, +                                                                         const gchar          *format_string, +                                                                         ...); +void                            g_variant_builder_add_parsed            (GVariantBuilder      *builder, +                                                                         const gchar          *format, +                                                                         ...); + +GVariant *                      g_variant_new                           (const gchar          *format_string, +                                                                         ...); +void                            g_variant_get                           (GVariant             *value, +                                                                         const gchar          *format_string, +                                                                         ...); +GVariant *                      g_variant_new_va                        (const gchar          *format_string, +                                                                         const gchar         **endptr, +                                                                         va_list              *app); +void                            g_variant_get_va                        (GVariant             *value, +                                                                         const gchar          *format_string, +                                                                         const gchar         **endptr, +                                                                         va_list              *app); + + +GVariant *                      g_variant_parse                         (const GVariantType   *type, +                                                                         const gchar          *text, +                                                                         const gchar          *limit, +                                                                         const gchar         **endptr, +                                                                         GError              **error); +GVariant *                      g_variant_new_parsed                    (const gchar          *format, +                                                                         ...); +GVariant *                      g_variant_new_parsed_va                 (const gchar          *format, +                                                                         va_list              *app); + +gint                            g_variant_compare                       (gconstpointer one, +                                                                         gconstpointer two); +G_END_DECLS + +#endif /* __G_VARIANT_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gvarianttype.h b/protocols/Sametime/src/glib/include/glib/gvarianttype.h new file mode 100644 index 0000000000..124fa46b59 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gvarianttype.h @@ -0,0 +1,334 @@ +/* + * Copyright © 2007, 2008 Ryan Lortie + * Copyright © 2009, 2010 Codethink Limited + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Ryan Lortie <desrt@desrt.ca> + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_VARIANT_TYPE_H__ +#define __G_VARIANT_TYPE_H__ + +#include <glib/gmessages.h> +#include <glib/gtypes.h> + +G_BEGIN_DECLS + +/** + * GVariantType: + * + * A type in the GVariant type system. + * + * Two types may not be compared by value; use g_variant_type_equal() or + * g_variant_type_is_subtype().  May be copied using + * g_variant_type_copy() and freed using g_variant_type_free(). + **/ +typedef struct _GVariantType GVariantType; + +/** + * G_VARIANT_TYPE_BOOLEAN: + * + * The type of a value that can be either %TRUE or %FALSE. + **/ +#define G_VARIANT_TYPE_BOOLEAN              ((const GVariantType *) "b") + +/** + * G_VARIANT_TYPE_BYTE: + * + * The type of an integer value that can range from 0 to 255. + **/ +#define G_VARIANT_TYPE_BYTE                 ((const GVariantType *) "y") + +/** + * G_VARIANT_TYPE_INT16: + * + * The type of an integer value that can range from -32768 to 32767. + **/ +#define G_VARIANT_TYPE_INT16                ((const GVariantType *) "n") + +/** + * G_VARIANT_TYPE_UINT16: + * + * The type of an integer value that can range from 0 to 65535. + * There were about this many people living in Toronto in the 1870s. + **/ +#define G_VARIANT_TYPE_UINT16               ((const GVariantType *) "q") + +/** + * G_VARIANT_TYPE_INT32: + * + * The type of an integer value that can range from -2147483648 to + * 2147483647. + **/ +#define G_VARIANT_TYPE_INT32                ((const GVariantType *) "i") + +/** + * G_VARIANT_TYPE_UINT32: + * + * The type of an integer value that can range from 0 to 4294967295. + * That's one number for everyone who was around in the late 1970s. + **/ +#define G_VARIANT_TYPE_UINT32               ((const GVariantType *) "u") + +/** + * G_VARIANT_TYPE_INT64: + * + * The type of an integer value that can range from + * -9223372036854775808 to 9223372036854775807. + **/ +#define G_VARIANT_TYPE_INT64                ((const GVariantType *) "x") + +/** + * G_VARIANT_TYPE_UINT64: + * + * The type of an integer value that can range from 0 to + * 18446744073709551616.  That's a really big number, but a Rubik's + * cube can have a bit more than twice as many possible positions. + **/ +#define G_VARIANT_TYPE_UINT64               ((const GVariantType *) "t") + +/** + * G_VARIANT_TYPE_DOUBLE: + * + * The type of a double precision IEEE754 floating point number. + * These guys go up to about 1.80e308 (plus and minus) but miss out on + * some numbers in between.  In any case, that's far greater than the + * estimated number of fundamental particles in the observable + * universe. + **/ +#define G_VARIANT_TYPE_DOUBLE               ((const GVariantType *) "d") + +/** + * G_VARIANT_TYPE_STRING: + * + * The type of a string.  "" is a string.  %NULL is not a string. + **/ +#define G_VARIANT_TYPE_STRING               ((const GVariantType *) "s") + +/** + * G_VARIANT_TYPE_OBJECT_PATH: + * + * The type of a DBus object reference.  These are strings of a + * specific format used to identify objects at a given destination on + * the bus. + * + * If you are not interacting with DBus, then there is no reason to make + * use of this type.  If you are, then the DBus specification contains a + * precise description of valid object paths. + **/ +#define G_VARIANT_TYPE_OBJECT_PATH          ((const GVariantType *) "o") + +/** + * G_VARIANT_TYPE_SIGNATURE: + * + * The type of a DBus type signature.  These are strings of a specific + * format used as type signatures for DBus methods and messages. + * + * If you are not interacting with DBus, then there is no reason to make + * use of this type.  If you are, then the DBus specification contains a + * precise description of valid signature strings. + **/ +#define G_VARIANT_TYPE_SIGNATURE            ((const GVariantType *) "g") + +/** + * G_VARIANT_TYPE_VARIANT: + * + * The type of a box that contains any other value (including another + * variant). + **/ +#define G_VARIANT_TYPE_VARIANT              ((const GVariantType *) "v") + +/** + * G_VARIANT_TYPE_HANDLE: + * + * The type of a 32bit signed integer value, that by convention, is used + * as an index into an array of file descriptors that are sent alongside + * a DBus message. + * + * If you are not interacting with DBus, then there is no reason to make + * use of this type. + **/ +#define G_VARIANT_TYPE_HANDLE               ((const GVariantType *) "h") + +/** + * G_VARIANT_TYPE_UNIT: + * + * The empty tuple type.  Has only one instance.  Known also as "triv" + * or "void". + **/ +#define G_VARIANT_TYPE_UNIT                 ((const GVariantType *) "()") + +/** + * G_VARIANT_TYPE_ANY: + * + * An indefinite type that is a supertype of every type (including + * itself). + **/ +#define G_VARIANT_TYPE_ANY                  ((const GVariantType *) "*") + +/** + * G_VARIANT_TYPE_BASIC: + * + * An indefinite type that is a supertype of every basic (ie: + * non-container) type. + **/ +#define G_VARIANT_TYPE_BASIC                ((const GVariantType *) "?") + +/** + * G_VARIANT_TYPE_MAYBE: + * + * An indefinite type that is a supertype of every maybe type. + **/ +#define G_VARIANT_TYPE_MAYBE                ((const GVariantType *) "m*") + +/** + * G_VARIANT_TYPE_ARRAY: + * + * An indefinite type that is a supertype of every array type. + **/ +#define G_VARIANT_TYPE_ARRAY                ((const GVariantType *) "a*") + +/** + * G_VARIANT_TYPE_TUPLE: + * + * An indefinite type that is a supertype of every tuple type, + * regardless of the number of items in the tuple. + **/ +#define G_VARIANT_TYPE_TUPLE                ((const GVariantType *) "r") + +/** + * G_VARIANT_TYPE_DICT_ENTRY: + * + * An indefinite type that is a supertype of every dictionary entry + * type. + **/ +#define G_VARIANT_TYPE_DICT_ENTRY           ((const GVariantType *) "{?*}") + +/** + * G_VARIANT_TYPE_DICTIONARY: + * + * An indefinite type that is a supertype of every dictionary type -- + * that is, any array type that has an element type equal to any + * dictionary entry type. + **/ +#define G_VARIANT_TYPE_DICTIONARY           ((const GVariantType *) "a{?*}") + +/** + * G_VARIANT_TYPE_STRING_ARRAY: + * + * The type of an array of strings. + **/ +#define G_VARIANT_TYPE_STRING_ARRAY         ((const GVariantType *) "as") + +/** + * G_VARIANT_TYPE_BYTESTRING: + * + * The type of an array of bytes.  This type is commonly used to pass + * around strings that may not be valid utf8.  In that case, the + * convention is that the nul terminator character should be included as + * the last character in the array. + **/ +#define G_VARIANT_TYPE_BYTESTRING           ((const GVariantType *) "ay") + +/** + * G_VARIANT_TYPE_BYTESTRING_ARRAY: + * + * The type of an array of byte strings (an array of arrays of bytes). + **/ +#define G_VARIANT_TYPE_BYTESTRING_ARRAY     ((const GVariantType *) "aay") + + +/** + * G_VARIANT_TYPE: + * @type_string: a well-formed #GVariantType type string + * + * Converts a string to a const #GVariantType.  Depending on the + * current debugging level, this function may perform a runtime check + * to ensure that @string is a valid GVariant type string. + * + * It is always a programmer error to use this macro with an invalid + * type string. + * + * Since 2.24 + **/ +#ifndef G_DISABLE_CHECKS +# define G_VARIANT_TYPE(type_string)            (g_variant_type_checked_ ((type_string))) +#else +# define G_VARIANT_TYPE(type_string)            ((const GVariantType *) (type_string)) +#endif + +/* type string checking */ +gboolean                        g_variant_type_string_is_valid          (const gchar         *type_string); +gboolean                        g_variant_type_string_scan              (const gchar         *string, +                                                                         const gchar         *limit, +                                                                         const gchar        **endptr); + +/* create/destroy */ +void                            g_variant_type_free                     (GVariantType        *type); +GVariantType *                  g_variant_type_copy                     (const GVariantType  *type); +GVariantType *                  g_variant_type_new                      (const gchar         *type_string); + +/* getters */ +gsize                           g_variant_type_get_string_length        (const GVariantType  *type); +const gchar *                   g_variant_type_peek_string              (const GVariantType  *type); +gchar *                         g_variant_type_dup_string               (const GVariantType  *type); + +/* classification */ +gboolean                        g_variant_type_is_definite              (const GVariantType  *type); +gboolean                        g_variant_type_is_container             (const GVariantType  *type); +gboolean                        g_variant_type_is_basic                 (const GVariantType  *type); +gboolean                        g_variant_type_is_maybe                 (const GVariantType  *type); +gboolean                        g_variant_type_is_array                 (const GVariantType  *type); +gboolean                        g_variant_type_is_tuple                 (const GVariantType  *type); +gboolean                        g_variant_type_is_dict_entry            (const GVariantType  *type); +gboolean                        g_variant_type_is_variant               (const GVariantType  *type); + +/* for hash tables */ +guint                           g_variant_type_hash                     (gconstpointer        type); +gboolean                        g_variant_type_equal                    (gconstpointer        type1, +                                                                         gconstpointer        type2); + +/* subtypes */ +gboolean                        g_variant_type_is_subtype_of            (const GVariantType  *type, +                                                                         const GVariantType  *supertype); + +/* type iterator interface */ +const GVariantType *            g_variant_type_element                  (const GVariantType  *type); +const GVariantType *            g_variant_type_first                    (const GVariantType  *type); +const GVariantType *            g_variant_type_next                     (const GVariantType  *type); +gsize                           g_variant_type_n_items                  (const GVariantType  *type); +const GVariantType *            g_variant_type_key                      (const GVariantType  *type); +const GVariantType *            g_variant_type_value                    (const GVariantType  *type); + +/* constructors */ +GVariantType *                  g_variant_type_new_array                (const GVariantType  *element); +GVariantType *                  g_variant_type_new_maybe                (const GVariantType  *element); +GVariantType *                  g_variant_type_new_tuple                (const GVariantType * const *items, +                                                                         gint                 length); +GVariantType *                  g_variant_type_new_dict_entry           (const GVariantType  *key, +                                                                         const GVariantType  *value); + +/*< private >*/ +const GVariantType *            g_variant_type_checked_                 (const gchar *); + +G_END_DECLS + +#endif /* __G_VARIANT_TYPE_H__ */ diff --git a/protocols/Sametime/src/glib/include/glib/gwin32.h b/protocols/Sametime/src/glib/include/glib/gwin32.h new file mode 100644 index 0000000000..5793335478 --- /dev/null +++ b/protocols/Sametime/src/glib/include/glib/gwin32.h @@ -0,0 +1,114 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000.  See the AUTHORS + * file for a list of people on the GLib Team.  See the ChangeLog + * files for a list of changes.  These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only <glib.h> can be included directly." +#endif + +#ifndef __G_WIN32_H__ +#define __G_WIN32_H__ + +#include <glib/gtypes.h> + +#ifdef G_PLATFORM_WIN32 + +G_BEGIN_DECLS + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +#ifdef G_OS_WIN32 + +/* + * To get prototypes for the following POSIXish functions, you have to + * include the indicated non-POSIX headers. The functions are defined + * in OLDNAMES.LIB (MSVC) or -lmoldname-msvc (mingw32). But note that + * for POSIX functions that take or return file names in the system + * codepage, in many cases you would want to use the GLib wrappers in + * gstdio.h and UTF-8 instead. + * + * getcwd: <direct.h> (MSVC), <io.h> (mingw32) + * getpid: <process.h> + * access: <io.h> + * unlink: <stdio.h> or <io.h> + * open, read, write, lseek, close: <io.h> + * rmdir: <io.h> + * pipe: <io.h> (actually, _pipe()) + */ + +/* For some POSIX functions that are not provided by the MS runtime, + * we provide emulation functions in glib, which are prefixed with + * g_win32_. Or that was the idea at some time, but there is just one + * of those: + */ +gint		g_win32_ftruncate	(gint		 f, +					 guint		 size); +#endif /* G_OS_WIN32 */ + +/* The MS setlocale uses locale names of the form "English_United + * States.1252" etc. We want the Unixish standard form "en", "zh_TW" + * etc. This function gets the current thread locale from Windows and + * returns it as a string of the above form for use in forming file + * names etc. The returned string should be deallocated with g_free(). + */ +gchar* 		g_win32_getlocale  (void); + +/* Translate a Win32 error code (as returned by GetLastError()) into + * the corresponding message. The returned string should be deallocated + * with g_free(). + */ +gchar*          g_win32_error_message (gint error); + +#ifndef G_DISABLE_DEPRECATED + +#define g_win32_get_package_installation_directory g_win32_get_package_installation_directory_utf8 +#define g_win32_get_package_installation_subdirectory g_win32_get_package_installation_subdirectory_utf8 + +gchar*          g_win32_get_package_installation_directory (const gchar *package, +							    const gchar *dll_name); + +gchar*          g_win32_get_package_installation_subdirectory (const gchar *package, +							       const gchar *dll_name, +							       const gchar *subdir); + +#endif + +gchar*          g_win32_get_package_installation_directory_of_module (gpointer hmodule); + +guint		g_win32_get_windows_version (void); + +gchar*          g_win32_locale_filename_from_utf8 (const gchar *utf8filename); + +/* As of GLib 2.14 we only support NT-based Windows */ +#define G_WIN32_IS_NT_BASED() TRUE +#define G_WIN32_HAVE_WIDECHAR_API() TRUE + +G_END_DECLS + +#endif	 /* G_PLATFORM_WIN32 */ + +#endif /* __G_WIN32_H__ */ diff --git a/protocols/Sametime/src/glib/include/glibconfig.h b/protocols/Sametime/src/glib/include/glibconfig.h new file mode 100644 index 0000000000..2fa4af628f --- /dev/null +++ b/protocols/Sametime/src/glib/include/glibconfig.h @@ -0,0 +1,284 @@ +/* glibconfig.h.win32.in. Originally merged from two versions of + * glibconfig.h, generated by the GLib configure script, for gcc and + * MSVC. + */ + +/* glibconfig.h + * + * This is a generated file.  Please modify 'glibconfig.h.win32.in' + */ + +#ifndef __G_LIBCONFIG_H__ +#define __G_LIBCONFIG_H__ + +#include <glib/gmacros.h> + +#include <limits.h> +#include <float.h> + +G_BEGIN_DECLS + +#define G_MINFLOAT	FLT_MIN +#define G_MAXFLOAT	FLT_MAX +#define G_MINDOUBLE	DBL_MIN +#define G_MAXDOUBLE	DBL_MAX +#define G_MINSHORT	SHRT_MIN +#define G_MAXSHORT	SHRT_MAX +#define G_MAXUSHORT	USHRT_MAX +#define G_MININT	INT_MIN +#define G_MAXINT	INT_MAX +#define G_MAXUINT	UINT_MAX +#define G_MINLONG	LONG_MIN +#define G_MAXLONG	LONG_MAX +#define G_MAXULONG	ULONG_MAX + +typedef signed char gint8; +typedef unsigned char guint8; +typedef signed short gint16; +typedef unsigned short guint16; +#define G_GINT16_MODIFIER "h" +#define G_GINT16_FORMAT "hi" +#define G_GUINT16_FORMAT "hu" +typedef signed int gint32; +typedef unsigned int guint32; +#define G_GINT32_MODIFIER "" +#define G_GINT32_FORMAT "i" +#define G_GUINT32_FORMAT "u" +#define G_HAVE_GINT64 1          /* deprecated, always true */ + +#ifndef _MSC_VER +G_GNUC_EXTENSION typedef signed long long gint64; +G_GNUC_EXTENSION typedef unsigned long long guint64; +#else /* _MSC_VER */ +typedef signed __int64 gint64; +typedef unsigned __int64 guint64; +#endif /* _MSC_VER */ + +#ifndef _MSC_VER +#define G_GINT64_CONSTANT(val)	(G_GNUC_EXTENSION (val##LL)) +#else /* _MSC_VER */ +#define G_GINT64_CONSTANT(val)	(val##i64) +#endif /* _MSC_VER */ +#ifndef _MSC_VER +#define G_GUINT64_CONSTANT(val)	(G_GNUC_EXTENSION (val##ULL)) +#else /* _MSC_VER */ +#define G_GUINT64_CONSTANT(val)	(val##Ui64) +#endif /* _MSC_VER */ +#define G_GINT64_MODIFIER "I64" +#define G_GINT64_FORMAT "I64i" +#define G_GUINT64_FORMAT "I64u" + +#if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64) + +#define GLIB_SIZEOF_VOID_P 8 +#define GLIB_SIZEOF_LONG   4 +#define GLIB_SIZEOF_SIZE_T 8 + +typedef signed long long gssize; +typedef unsigned long long gsize; +#define G_GSIZE_MODIFIER "I64" +#define G_GSSIZE_FORMAT "I64d" +#define G_GSIZE_FORMAT "I64u" + +#define G_MAXSIZE	G_MAXUINT64 +#define G_MINSSIZE	G_MININT64 +#define G_MAXSSIZE	G_MAXINT64 + +#else + +#define GLIB_SIZEOF_VOID_P 4 +#define GLIB_SIZEOF_LONG   4 +#define GLIB_SIZEOF_SIZE_T 4 + +typedef signed int gssize; +typedef unsigned int gsize; +#define G_GSIZE_MODIFIER "" +#define G_GSSIZE_FORMAT "i" +#define G_GSIZE_FORMAT "u" + +#define G_MAXSIZE	G_MAXUINT +#define G_MINSSIZE	G_MININT +#define G_MAXSSIZE	G_MAXINT + +#endif + +typedef gint64 goffset; +#define G_MINOFFSET	G_MININT64 +#define G_MAXOFFSET	G_MAXINT64 + +#define G_GOFFSET_MODIFIER      G_GINT64_MODIFIER +#define G_GOFFSET_FORMAT        G_GINT64_FORMAT +#define G_GOFFSET_CONSTANT(val) G_GINT64_CONSTANT(val) + + +#ifndef _WIN64 + +#define GPOINTER_TO_INT(p)	((gint)   (p)) +#define GPOINTER_TO_UINT(p)	((guint)  (p)) + +#define GINT_TO_POINTER(i)	((gpointer)  (i)) +#define GUINT_TO_POINTER(u)	((gpointer)  (u)) + +typedef signed int gintptr; +typedef unsigned int guintptr; + +#define G_GINTPTR_MODIFIER      "" +#define G_GINTPTR_FORMAT        "i" +#define G_GUINTPTR_FORMAT       "u" + +#else + +#define GPOINTER_TO_INT(p)	((gint)  (gint64) (p)) +#define GPOINTER_TO_UINT(p)	((guint) (guint64) (p)) + +#define GINT_TO_POINTER(i)	((gpointer) (gint64) (i)) +#define GUINT_TO_POINTER(u)	((gpointer) (guint64) (u)) + +#ifndef _MSC_VER +typedef signed long long gintptr; +typedef unsigned long long guintptr; +#else +typedef signed __int64 gintptr; +typedef unsigned __int64 guintptr; +#endif + +#define G_GINTPTR_MODIFIER      "I64" +#define G_GINTPTR_FORMAT        "I64i" +#define G_GUINTPTR_FORMAT       "I64u" + +#endif + +#ifdef NeXT /* @#%@! NeXTStep */ +# define g_ATEXIT(proc)	(!atexit (proc)) +#else +# define g_ATEXIT(proc)	(atexit (proc)) +#endif + +#define g_memmove(dest,src,len) G_STMT_START { memmove ((dest), (src), (len)); } G_STMT_END + +#define GLIB_MAJOR_VERSION 2 +#define GLIB_MINOR_VERSION 26 +#define GLIB_MICRO_VERSION 1 + +#define G_OS_WIN32 +#define G_PLATFORM_WIN32 + + +#ifndef _MSC_VER +#define G_VA_COPY	va_copy +#endif /* not _MSC_VER */ + +#ifdef	__cplusplus +#define	G_HAVE_INLINE	1 +#else	/* !__cplusplus */ +#ifndef _MSC_VER +#define G_HAVE_INLINE 1 +#endif /* _MSC_VER */ +#define G_HAVE___INLINE 1 +#if !defined(_MSC_VER) && !defined(__DMC__) +#define G_HAVE___INLINE__ 1 +#endif /* !_MSC_VER and !__DMC__ */ +#endif	/* !__cplusplus */ + +#define G_CAN_INLINE	1 + +#ifndef _MSC_VER +#define G_HAVE_ISO_VARARGS 1 + +/* gcc-2.95.x supports both gnu style and ISO varargs, but if -ansi + * is passed ISO vararg support is turned off, and there is no work + * around to turn it on, so we unconditionally turn it off. + */ +#if __GNUC__ == 2 && __GNUC_MINOR__ == 95 +#  undef G_HAVE_ISO_VARARGS +#endif + +#define G_HAVE_GNUC_VARARGS 1 +#else /* _MSC_VER */ +/* varargs macros available since msvc8 (vs2005) */ +#  if _MSC_VER >= 1400 +#    define G_HAVE_ISO_VARARGS 1 +#   endif +#endif /* not _MSC_VER */ +#define G_HAVE_GROWING_STACK 0 + +#define G_GNUC_INTERNAL + +#define G_THREADS_ENABLED +#define G_THREADS_IMPL_WIN32 +typedef struct _GMutex* GStaticMutex; +#define G_STATIC_MUTEX_INIT NULL +#define g_static_mutex_get_mutex(mutex) \ +  (g_static_mutex_get_mutex_impl_shortcut (mutex)) +/* This represents a system thread as used by the implementation. An + * alien implementaion, as loaded by g_thread_init can only count on + * "sizeof (gpointer)" bytes to store their info. We however need more + * for some of our native implementations. */ +typedef union _GSystemThread GSystemThread; +union _GSystemThread +{ +#ifndef _WIN64 +  char   data[4]; +#else +  char   data[8]; +#endif +  double dummy_double; +  void  *dummy_pointer; +  long   dummy_long; +}; + +#define GINT16_TO_LE(val)	((gint16) (val)) +#define GUINT16_TO_LE(val)	((guint16) (val)) +#define GINT16_TO_BE(val)	((gint16) GUINT16_SWAP_LE_BE (val)) +#define GUINT16_TO_BE(val)	(GUINT16_SWAP_LE_BE (val)) +#define GINT32_TO_LE(val)	((gint32) (val)) +#define GUINT32_TO_LE(val)	((guint32) (val)) +#define GINT32_TO_BE(val)	((gint32) GUINT32_SWAP_LE_BE (val)) +#define GUINT32_TO_BE(val)	(GUINT32_SWAP_LE_BE (val)) +#define GINT64_TO_LE(val)	((gint64) (val)) +#define GUINT64_TO_LE(val)	((guint64) (val)) +#define GINT64_TO_BE(val)	((gint64) GUINT64_SWAP_LE_BE (val)) +#define GUINT64_TO_BE(val)	(GUINT64_SWAP_LE_BE (val)) +#define GLONG_TO_LE(val)	((glong) GINT32_TO_LE (val)) +#define GULONG_TO_LE(val)	((gulong) GUINT32_TO_LE (val)) +#define GLONG_TO_BE(val)	((glong) GINT32_TO_BE (val)) +#define GULONG_TO_BE(val)	((gulong) GUINT32_TO_BE (val)) +#define GINT_TO_LE(val)		((gint) GINT32_TO_LE (val)) +#define GUINT_TO_LE(val)	((guint) GUINT32_TO_LE (val)) +#define GINT_TO_BE(val)		((gint) GINT32_TO_BE (val)) +#define GUINT_TO_BE(val)	((guint) GUINT32_TO_BE (val)) +#define GSIZE_TO_LE(val)	((gsize) GUINT32_TO_LE (val)) +#define GSSIZE_TO_LE(val)	((gssize) GINT32_TO_LE (val)) +#define GSIZE_TO_BE(val)	((gsize) GUINT32_TO_BE (val)) +#define GSSIZE_TO_BE(val)	((gssize) GINT32_TO_BE (val)) +#define G_BYTE_ORDER G_LITTLE_ENDIAN + +#define GLIB_SYSDEF_POLLIN =1 +#define GLIB_SYSDEF_POLLOUT =4 +#define GLIB_SYSDEF_POLLPRI =2 +#define GLIB_SYSDEF_POLLHUP =16 +#define GLIB_SYSDEF_POLLERR =8 +#define GLIB_SYSDEF_POLLNVAL =32 + +#define G_MODULE_SUFFIX "dll" + +/* A GPid is an abstraction for a process "handle". It is *not* an + * abstraction for a process identifier in general. GPid is used in + * GLib only for descendant processes spawned with the g_spawn* + * functions. On POSIX there is no "process handle" concept as such, + * but on Windows a GPid is a handle to a process, a kind of pointer, + * not a process identifier. + */ +typedef void * GPid; + +#define GLIB_SYSDEF_AF_UNIX 1 +#define GLIB_SYSDEF_AF_INET 2 +#define GLIB_SYSDEF_AF_INET6 23 + +#define GLIB_SYSDEF_MSG_OOB       1 +#define GLIB_SYSDEF_MSG_PEEK      2 +#define GLIB_SYSDEF_MSG_DONTROUTE 4 + +G_END_DECLS + +#endif /* GLIBCONFIG_H */ diff --git a/protocols/Sametime/src/glib/lib32/glib-2.0.lib b/protocols/Sametime/src/glib/lib32/glib-2.0.lib Binary files differnew file mode 100644 index 0000000000..9ba0ee06e7 --- /dev/null +++ b/protocols/Sametime/src/glib/lib32/glib-2.0.lib diff --git a/protocols/Sametime/src/glib/lib64/glib-2.0.lib b/protocols/Sametime/src/glib/lib64/glib-2.0.lib Binary files differnew file mode 100644 index 0000000000..52616ec596 --- /dev/null +++ b/protocols/Sametime/src/glib/lib64/glib-2.0.lib diff --git a/protocols/Sametime/src/meanwhile/AUTHORS b/protocols/Sametime/src/meanwhile/AUTHORS new file mode 100644 index 0000000000..76f993f550 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/AUTHORS @@ -0,0 +1,10 @@ + +Maintainer: +Christopher (siege) O'Brien  <siege@preoccupied.net> + +Packager: +Stepher Dawkins + +Patches: +Chris Ross +Jeremy Kerr diff --git a/protocols/Sametime/src/meanwhile/LICENSE b/protocols/Sametime/src/meanwhile/LICENSE new file mode 100644 index 0000000000..92b8903ff3 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/LICENSE @@ -0,0 +1,481 @@ +		  GNU LIBRARY GENERAL PUBLIC LICENSE +		       Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. +    		    59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL.  It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + +			    Preamble + +  The licenses for most software are designed to take away your +freedom to share and change it.  By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + +  This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it.  You can use it for +your libraries, too. + +  When we speak of free software, we are referring to freedom, not +price.  Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +  To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + +  For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you.  You must make sure that they, too, receive or can get the source +code.  If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it.  And you must show them these terms so they know their rights. + +  Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + +  Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library.  If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + +  Finally, any free program is threatened constantly by software +patents.  We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software.  To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + +  Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs.  This +license, the GNU Library General Public License, applies to certain +designated libraries.  This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + +  The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it.  Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program.  However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + +  Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries.  We +concluded that weaker conditions might promote sharing better. + +  However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves.  This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them.  (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.)  The hope is that this +will lead to faster development of free libraries. + +  The precise terms and conditions for copying, distribution and +modification follow.  Pay close attention to the difference between a +"work based on the library" and a "work that uses the library".  The +former contains code derived from the library, while the latter only +works together with the library. + +  Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + +		  GNU LIBRARY GENERAL PUBLIC LICENSE +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +  0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License").  Each licensee is +addressed as "you". + +  A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + +  The "Library", below, refers to any such software library or work +which has been distributed under these terms.  A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language.  (Hereinafter, translation is +included without limitation in the term "modification".) + +  "Source code" for a work means the preferred form of the work for +making modifications to it.  For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + +  Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope.  The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it).  Whether that is true depends on what the Library does +and what the program that uses the Library does. +   +  1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + +  You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + +  2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +    a) The modified work must itself be a software library. + +    b) You must cause the files modified to carry prominent notices +    stating that you changed the files and the date of any change. + +    c) You must cause the whole of the work to be licensed at no +    charge to all third parties under the terms of this License. + +    d) If a facility in the modified Library refers to a function or a +    table of data to be supplied by an application program that uses +    the facility, other than as an argument passed when the facility +    is invoked, then you must make a good faith effort to ensure that, +    in the event an application does not supply such function or +    table, the facility still operates, and performs whatever part of +    its purpose remains meaningful. + +    (For example, a function in a library to compute square roots has +    a purpose that is entirely well-defined independent of the +    application.  Therefore, Subsection 2d requires that any +    application-supplied function or table used by this function must +    be optional: if the application does not supply it, the square +    root function must still compute square roots.) + +These requirements apply to the modified work as a whole.  If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works.  But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +  3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library.  To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License.  (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.)  Do not make any other change in +these notices. + +  Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + +  This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + +  4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + +  If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + +  5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library".  Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + +  However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library".  The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + +  When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library.  The +threshold for this to be true is not precisely defined by law. + +  If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work.  (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + +  Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + +  6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + +  You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License.  You must supply a copy of this License.  If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License.  Also, you must do one +of these things: + +    a) Accompany the work with the complete corresponding +    machine-readable source code for the Library including whatever +    changes were used in the work (which must be distributed under +    Sections 1 and 2 above); and, if the work is an executable linked +    with the Library, with the complete machine-readable "work that +    uses the Library", as object code and/or source code, so that the +    user can modify the Library and then relink to produce a modified +    executable containing the modified Library.  (It is understood +    that the user who changes the contents of definitions files in the +    Library will not necessarily be able to recompile the application +    to use the modified definitions.) + +    b) Accompany the work with a written offer, valid for at +    least three years, to give the same user the materials +    specified in Subsection 6a, above, for a charge no more +    than the cost of performing this distribution. + +    c) If distribution of the work is made by offering access to copy +    from a designated place, offer equivalent access to copy the above +    specified materials from the same place. + +    d) Verify that the user has already received a copy of these +    materials or that you have already sent this user a copy. + +  For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it.  However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + +  It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system.  Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + +  7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + +    a) Accompany the combined library with a copy of the same work +    based on the Library, uncombined with any other library +    facilities.  This must be distributed under the terms of the +    Sections above. + +    b) Give prominent notice with the combined library of the fact +    that part of it is a work based on the Library, and explaining +    where to find the accompanying uncombined form of the same work. + +  8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License.  Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License.  However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + +  9. You are not required to accept this License, since you have not +signed it.  However, nothing else grants you permission to modify or +distribute the Library or its derivative works.  These actions are +prohibited by law if you do not accept this License.  Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +  10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions.  You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +  11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License.  If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all.  For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices.  Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +  12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded.  In such case, this License incorporates the limitation as if +written in the body of this License. + +  13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number.  If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation.  If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + +  14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission.  For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this.  Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + +			    NO WARRANTY + +  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +		     END OF TERMS AND CONDITIONS + +           How to Apply These Terms to Your New Libraries + +  If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change.  You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + +  To apply these terms, attach the following notices to the library.  It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + +    <one line to give the library's name and a brief idea of what it does.> +    Copyright (C) <year>  <name of author> + +    This library is free software; you can redistribute it and/or +    modify it under the terms of the GNU Library General Public +    License as published by the Free Software Foundation; either +    version 2 of the License, or (at your option) any later version. + +    This library is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +    Library General Public License for more details. + +    You should have received a copy of the GNU Library General Public +    License along with this library; if not, write to the Free +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary.  Here is a sample; alter the names: + +  Yoyodyne, Inc., hereby disclaims all copyright interest in the +  library `Frob' (a library for tweaking knobs) written by James Random Hacker. + +  <signature of Ty Coon>, 1 April 1990 +  Ty Coon, President of Vice + +That's all there is to it! diff --git a/protocols/Sametime/src/meanwhile/README b/protocols/Sametime/src/meanwhile/README new file mode 100644 index 0000000000..fb83fec75e --- /dev/null +++ b/protocols/Sametime/src/meanwhile/README @@ -0,0 +1,39 @@ + +===================== +The Meanwhile Project +===================== + +http://meanwhile.sourceforge.net/ +Christopher (siege) O'Brien <siege@preoccupied.net> + +Meanwhile is a library for connecting to a LIM (Lotus Instant +Messaging, formerly Lotus Sametime, formerly VPBuddy) community. It +uses a protocol based in part off of the IMPP draft(*1), and in part +off of traces of TCP sessions from existing clients. + +Meanwhile-python is a set of Python wrappers for the Meanwhile library + +The gaim-meanwhile plugin allows Gaim to connect to a Lotus Sametime +(tm) community using a compiled-in version of libMeanwhile. + +See INSTALL for instructions on building and installing + + +======= +License +======= + +Meanwhile and Meanwhile-python are released under the LGPL. See +LICENSE for the full license text and terms. + +Meanwhile-gaim is released under the GPL + + +========= +Footnotes +========= + +(*1) draft-houri-sametime-community-client-00.txt submitted to the +IETF as a draft proposal for the IMPP working group charter. + + diff --git a/protocols/Sametime/src/meanwhile/src/channel.c b/protocols/Sametime/src/meanwhile/src/channel.c new file mode 100644 index 0000000000..a9dc2836be --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/channel.c @@ -0,0 +1,972 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <glib.h> +#include <glib/ghash.h> +#include <glib/glist.h> +#include <string.h> + +#include "mw_channel.h" +#include "mw_cipher.h" +#include "mw_debug.h" +#include "mw_error.h" +#include "mw_message.h" +#include "mw_service.h" +#include "mw_session.h" +#include "mw_util.h" + + +/** @todo reorganize this file, stuff is just strewn about */ + + +struct mwChannel { + +  /** session this channel belongs to */ +  struct mwSession *session; + +  enum mwChannelState state; + +  /** creator for incoming channel, target for outgoing channel */ +  struct mwLoginInfo user; + +  /* similar to data from the CreateCnl message in 8.4.1.7 */ +  guint32 reserved;    /**< special, unknown meaning */ +  guint32 id;          /**< channel ID */ +  guint32 service;     /**< service ID */ +  guint32 proto_type;  /**< service protocol type */ +  guint32 proto_ver;   /**< service protocol version */ +  guint32 options;     /**< channel options */ + +  struct mwOpaque addtl_create; +  struct mwOpaque addtl_accept; + +  /** all those supported ciphers */ +  GHashTable *supported; +  guint16 offered_policy;  /**< @see enum mwEncryptPolicy */ +  guint16 policy;          /**< @see enum mwEncryptPolicy */ + +  /** cipher information determined at channel acceptance */ +  struct mwCipherInstance *cipher; + +  /** statistics table */ +  GHashTable *stats; + +  GSList *outgoing_queue;     /**< queued outgoing messages */ +  GSList *incoming_queue;     /**< queued incoming messages */ + +  struct mw_datum srvc_data;  /**< service-specific data */ +}; + + +struct mwChannelSet { +  struct mwSession *session;  /**< owning session */ +  GHashTable *map;            /**< map of all channels, by ID */ +  guint32 counter;            /**< counter for outgoing ID */ +}; + + +static void flush_channel(struct mwChannel *); + + +static const char *state_str(enum mwChannelState state) { +  switch(state) { +  case mwChannel_NEW:      return "new"; +  case mwChannel_INIT:     return "initializing"; +  case mwChannel_WAIT:     return "waiting"; +  case mwChannel_OPEN:     return "open"; +  case mwChannel_DESTROY:  return "closing"; +  case mwChannel_ERROR:    return "error"; + +  case mwChannel_UNKNOWN:  /* fall through */ +  default:                 return "UNKNOWN"; +  } +} + + +static void state(struct mwChannel *chan, enum mwChannelState state, +		  guint32 err_code) { + +  g_return_if_fail(chan != NULL); + +  if(chan->state == state) return; + +  chan->state = state; + +  if(err_code) { +    g_message("channel 0x%08x state: %s (0x%08x)", +	      chan->id, state_str(state), err_code); +  } else { +    g_message("channel 0x%08x state: %s", chan->id, state_str(state)); +  } +} + + +static gpointer get_stat(struct mwChannel *chan, +			 enum mwChannelStatField field) { + +  return g_hash_table_lookup(chan->stats, (gpointer) field); +} + + +static void set_stat(struct mwChannel *chan, enum mwChannelStatField field, +		     gpointer val) { + +  g_hash_table_insert(chan->stats, (gpointer) field, val); +} + +/// Miranda NG adaptation start - MSVC +//#define incr_stat(chan, field, incr) \ +//  set_stat(chan, field, get_stat(chan, field) + incr) +#define incr_stat(chan, field, incr) \ +  set_stat(chan, field, (char*)get_stat(chan, field) + incr) +/// Miranda NG adaptation end + +#define timestamp_stat(chan, field) \ +  set_stat(chan, field, (gpointer) time(NULL)) + + +static void sup_free(gpointer a) { +  mwCipherInstance_free(a); +} + + +static struct mwCipherInstance * +get_supported(struct mwChannel *chan, guint16 id) { + +  guint32 cid = (guint32) id; +  return g_hash_table_lookup(chan->supported, GUINT_TO_POINTER(cid)); +} + + +static void put_supported(struct mwChannel *chan, +			  struct mwCipherInstance *ci) { + +  struct mwCipher *cipher = mwCipherInstance_getCipher(ci); +  guint32 cid = (guint32) mwCipher_getType(cipher); +  g_hash_table_insert(chan->supported, GUINT_TO_POINTER(cid), ci); +} + + +struct mwChannel *mwChannel_newIncoming(struct mwChannelSet *cs, guint32 id) { +  struct mwChannel *chan; + +  g_return_val_if_fail(cs != NULL, NULL); +  g_return_val_if_fail(cs->session != NULL, NULL); + +  chan = g_new0(struct mwChannel, 1); +  chan->state = mwChannel_NEW; +  chan->session = cs->session; +  chan->id = id; + +  chan->stats = g_hash_table_new(g_direct_hash, g_direct_equal); + +  chan->supported = g_hash_table_new_full(g_direct_hash, g_direct_equal, +					  NULL, sup_free); + +  g_hash_table_insert(cs->map, GUINT_TO_POINTER(id), chan); + +  state(chan, mwChannel_WAIT, 0); + +  return chan; +} + + +struct mwChannel *mwChannel_newOutgoing(struct mwChannelSet *cs) { +  guint32 id; +  struct mwChannel *chan; + +  g_return_val_if_fail(cs != NULL, NULL); +  g_return_val_if_fail(cs->map != NULL, NULL); + +  /* grab the next id, and try to make sure there isn't already a +     channel using it */ +  do { +    id = ++cs->counter; +  } while(g_hash_table_lookup(cs->map, GUINT_TO_POINTER(id))); +   +  chan = mwChannel_newIncoming(cs, id); +  state(chan, mwChannel_INIT, 0); + +  return chan; +} + + +guint32 mwChannel_getId(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, 0); +  return chan->id; +} + + +struct mwSession *mwChannel_getSession(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, NULL); +  return chan->session; +} + + +guint32 mwChannel_getServiceId(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, 0); +  return chan->service; +} + + +struct mwService *mwChannel_getService(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, NULL); +  return mwSession_getService(chan->session, chan->service); +} + + +void mwChannel_setService(struct mwChannel *chan, struct mwService *srvc) { +  g_return_if_fail(chan != NULL); +  g_return_if_fail(srvc != NULL); +  g_return_if_fail(chan->state == mwChannel_INIT); +  chan->service = mwService_getType(srvc); +} + + +gpointer mwChannel_getServiceData(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, NULL); +  return mw_datum_get(&chan->srvc_data); +} + + +void mwChannel_setServiceData(struct mwChannel *chan, +			      gpointer data, GDestroyNotify clean) { + +  g_return_if_fail(chan != NULL); +  mw_datum_set(&chan->srvc_data, data, clean); +} + + +void mwChannel_removeServiceData(struct mwChannel *chan) { +  g_return_if_fail(chan != NULL); +  mw_datum_clear(&chan->srvc_data); +} + + +guint32 mwChannel_getProtoType(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, 0x00); +  return chan->proto_type; +} + + +void mwChannel_setProtoType(struct mwChannel *chan, guint32 proto_type) { +  g_return_if_fail(chan != NULL); +  g_return_if_fail(chan->state == mwChannel_INIT); +  chan->proto_type = proto_type; +} + + +guint32 mwChannel_getProtoVer(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, 0x00); +  return chan->proto_ver; +} + + +void mwChannel_setProtoVer(struct mwChannel *chan, guint32 proto_ver) { +  g_return_if_fail(chan != NULL); +  g_return_if_fail(chan->state == mwChannel_INIT); +  chan->proto_ver = proto_ver; +} + + +guint16 mwChannel_getEncryptPolicy(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, 0x00); +  return chan->policy; +} + + +guint32 mwChannel_getOptions(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, 0x00); +  return chan->options; +} + + +void mwChannel_setOptions(struct mwChannel *chan, guint32 options) { +  g_return_if_fail(chan != NULL); +  g_return_if_fail(chan->state == mwChannel_INIT); +  chan->options = options; +} + + +struct mwLoginInfo *mwChannel_getUser(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, NULL); +  return &chan->user; +} + + +struct mwOpaque *mwChannel_getAddtlCreate(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, NULL); +  return &chan->addtl_create; +} + + +struct mwOpaque *mwChannel_getAddtlAccept(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, NULL); +  return &chan->addtl_accept; +} + + +struct mwCipherInstance * +mwChannel_getCipherInstance(struct mwChannel *chan) { + +  g_return_val_if_fail(chan != NULL, NULL); +  return chan->cipher; +} + + +enum mwChannelState mwChannel_getState(struct mwChannel *chan) { +  g_return_val_if_fail(chan != NULL, mwChannel_UNKNOWN); +  return chan->state; +} + + +gpointer mwChannel_getStatistic(struct mwChannel *chan, +				enum mwChannelStatField stat) { +   +  g_return_val_if_fail(chan != NULL, 0); +  g_return_val_if_fail(chan->stats != NULL, 0); + +  return get_stat(chan, stat); +} + + +/* send a channel create message */ +int mwChannel_create(struct mwChannel *chan) { +  struct mwMsgChannelCreate *msg; +  GList *list, *l; +  int ret; + +  g_return_val_if_fail(chan != NULL, -1); +  g_return_val_if_fail(chan->state == mwChannel_INIT, -1); +  g_return_val_if_fail(mwChannel_isOutgoing(chan), -1); + +  msg = (struct mwMsgChannelCreate *) +    mwMessage_new(mwMessage_CHANNEL_CREATE); + +  msg->channel = chan->id; +  msg->target.user = g_strdup(chan->user.user_id); +  msg->target.community = g_strdup(chan->user.community); +  msg->service = chan->service; +  msg->proto_type = chan->proto_type; +  msg->proto_ver = chan->proto_ver; +  msg->options = chan->options; +  mwOpaque_clone(&msg->addtl, &chan->addtl_create); + +  list = mwChannel_getSupportedCipherInstances(chan); +  if(list) { +    /* offer what we have */ +    for(l = list; l; l = l->next) { +      struct mwEncryptItem *ei = mwCipherInstance_offer(l->data); +      msg->encrypt.items = g_list_append(msg->encrypt.items, ei); +    } + +    /* we're easy to get along with */ +    chan->offered_policy = mwEncrypt_WHATEVER; +    g_list_free(list); + +  } else { +    /* we apparently don't support anything */ +    chan->offered_policy = mwEncrypt_NONE; +  } + +  msg->encrypt.mode = chan->offered_policy; +  msg->encrypt.extra = chan->offered_policy; +   +  ret = mwSession_send(chan->session, MW_MESSAGE(msg)); +  mwMessage_free(MW_MESSAGE(msg)); + +  state(chan, (ret)? mwChannel_ERROR: mwChannel_WAIT, ret); + +  return ret; +} + + +static void channel_open(struct mwChannel *chan) { +  state(chan, mwChannel_OPEN, 0); +  timestamp_stat(chan, mwChannelStat_OPENED_AT); +  flush_channel(chan); +} + + +int mwChannel_accept(struct mwChannel *chan) { +  struct mwSession *session; +  struct mwMsgChannelAccept *msg; +  struct mwCipherInstance *ci; + +  int ret; + +  g_return_val_if_fail(chan != NULL, -1); +  g_return_val_if_fail(mwChannel_isIncoming(chan), -1); +  g_return_val_if_fail(chan->state == mwChannel_WAIT, -1); + +  session = chan->session; +  g_return_val_if_fail(session != NULL, -1); + +  msg = (struct mwMsgChannelAccept *) +    mwMessage_new(mwMessage_CHANNEL_ACCEPT); + +  msg->head.channel = chan->id; +  msg->service = chan->service; +  msg->proto_type = chan->proto_type; +  msg->proto_ver = chan->proto_ver; +  mwOpaque_clone(&msg->addtl, &chan->addtl_accept); + +  ci = chan->cipher; + +  if(! ci) { +    /* automatically select a cipher if one hasn't been already */ + +    switch(chan->offered_policy) { +    case mwEncrypt_NONE: +      mwChannel_selectCipherInstance(chan, NULL); +      break; +       +    case mwEncrypt_RC2_40: +      ci = get_supported(chan, mwCipher_RC2_40); +      mwChannel_selectCipherInstance(chan, ci); +      break; + +    case mwEncrypt_RC2_128: +      ci = get_supported(chan, mwCipher_RC2_128); +      mwChannel_selectCipherInstance(chan, ci); +      break; +       +    case mwEncrypt_WHATEVER: +    case mwEncrypt_ALL: +    default: +      { +	GList *l, *ll; + +	l = mwChannel_getSupportedCipherInstances(chan); +	if(l) { +	  /* nobody selected a cipher, so we'll just pick the last in +	     the list of available ones */ +	  for(ll = l; ll->next; ll = ll->next); +	  ci = ll->data; +	  g_list_free(l); +	   +	  mwChannel_selectCipherInstance(chan, ci); +	   +	} else { +	  /* this may cause breakage, but there's really nothing else +	     we can do. They want something we can't provide. If they +	     don't like it, then they'll error the channel out */ +	  mwChannel_selectCipherInstance(chan, NULL); +	} +      } +    } +  } + +  msg->encrypt.mode = chan->policy; /* set in selectCipherInstance */ +  msg->encrypt.extra = chan->offered_policy; + +  if(chan->cipher) { +    msg->encrypt.item = mwCipherInstance_accept(chan->cipher); +  } + +  ret = mwSession_send(session, MW_MESSAGE(msg)); +  mwMessage_free(MW_MESSAGE(msg)); + +  if(ret) { +    state(chan, mwChannel_ERROR, ret); +  } else { +    channel_open(chan); +  } + +  return ret; +} + + +static void channel_free(struct mwChannel *chan) { +  struct mwSession *s; +  struct mwMessage *msg; +  GSList *l; + +  /* maybe no warning in the future */ +  g_return_if_fail(chan != NULL); + +  s = chan->session; + +  mwLoginInfo_clear(&chan->user); +  mwOpaque_clear(&chan->addtl_create); +  mwOpaque_clear(&chan->addtl_accept); + +  if(chan->supported) { +    g_hash_table_destroy(chan->supported); +    chan->supported = NULL; +  } + +  if(chan->stats) { +    g_hash_table_destroy(chan->stats); +    chan->stats = NULL; +  } +   +  mwCipherInstance_free(chan->cipher); + +  /* clean up the outgoing queue */ +  for(l = chan->outgoing_queue; l; l = l->next) { +    msg = (struct mwMessage *) l->data; +    l->data = NULL; +    mwMessage_free(msg); +  } +  g_slist_free(chan->outgoing_queue); + +  /* clean up the incoming queue */ +  for(l = chan->incoming_queue; l; l = l->next) { +    msg = (struct mwMessage *) l->data; +    l->data = NULL; +    mwMessage_free(msg); +  } +  g_slist_free(chan->incoming_queue); + +  g_free(chan); +} + + +int mwChannel_destroy(struct mwChannel *chan, +		      guint32 reason, struct mwOpaque *info) { + +  struct mwMsgChannelDestroy *msg; +  struct mwSession *session; +  struct mwChannelSet *cs; +  int ret; + +  /* may make this not a warning in the future */ +  g_return_val_if_fail(chan != NULL, 0); + +  state(chan, reason? mwChannel_ERROR: mwChannel_DESTROY, reason); + +  session = chan->session; +  g_return_val_if_fail(session != NULL, -1); + +  cs = mwSession_getChannels(session); +  g_return_val_if_fail(cs != NULL, -1); + +  /* compose the message */ +  msg = (struct mwMsgChannelDestroy *) +    mwMessage_new(mwMessage_CHANNEL_DESTROY); +  msg->head.channel = chan->id; +  msg->reason = reason; +  if(info) mwOpaque_clone(&msg->data, info); + +  /* remove the channel from the channel set */ +  g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id)); +   +  /* send the message */ +  ret = mwSession_send(session, (struct mwMessage *) msg); +  mwMessage_free(MW_MESSAGE(msg)); + +  return ret; +} + + +static void queue_outgoing(struct mwChannel *chan, +			   struct mwMsgChannelSend *msg) { +  // Miranda NG adaptation +  //g_info("queue_outgoing, channel 0x%08x", chan->id); +  g_message("queue_outgoing, channel 0x%08x", chan->id); +  chan->outgoing_queue = g_slist_append(chan->outgoing_queue, msg); +} + + +static int channel_send(struct mwChannel *chan, +			struct mwMsgChannelSend *msg) { + +  int ret = 0; + +  /* if the channel is open, send and free the message. Otherwise, +     queue the message to be sent once the channel is finally +     opened */ + +  if(chan->state == mwChannel_OPEN) { +    ret = mwSession_send(chan->session, (struct mwMessage *) msg); +    mwMessage_free(MW_MESSAGE(msg)); + +  } else { +    queue_outgoing(chan, msg); +  } + +  return ret; +} + + +int mwChannel_sendEncrypted(struct mwChannel *chan, +			    guint32 type, struct mwOpaque *data, +			    gboolean encrypt) { + +  struct mwMsgChannelSend *msg; + +  g_return_val_if_fail(chan != NULL, -1); + +  msg = (struct mwMsgChannelSend *) mwMessage_new(mwMessage_CHANNEL_SEND); +  msg->head.channel = chan->id; +  msg->type = type; + +  mwOpaque_clone(&msg->data, data); + +  if(encrypt && chan->cipher) { +    msg->head.options = mwMessageOption_ENCRYPT; +    mwCipherInstance_encrypt(chan->cipher, &msg->data); +  } + +  return channel_send(chan, msg);   +} + + +int mwChannel_send(struct mwChannel *chan, guint32 type, +		   struct mwOpaque *data) { + +  return mwChannel_sendEncrypted(chan, type, data, TRUE); +} + + +static void queue_incoming(struct mwChannel *chan, +			   struct mwMsgChannelSend *msg) { + +  /* we clone the message, because session_process will clear it once +     we return */ + +  struct mwMsgChannelSend *m = g_new0(struct mwMsgChannelSend, 1); +  m->head.type = msg->head.type; +  m->head.options = msg->head.options; +  m->head.channel = msg->head.channel; +  mwOpaque_clone(&m->head.attribs, &msg->head.attribs); + +  m->type = msg->type; +  mwOpaque_clone(&m->data, &msg->data); + +  // Miranda NG adaptation +  //g_info("queue_incoming, channel 0x%08x", chan->id); +  g_message("queue_incoming, channel 0x%08x", chan->id); +  chan->incoming_queue = g_slist_append(chan->incoming_queue, m); +} + + +static void channel_recv(struct mwChannel *chan, +			 struct mwMsgChannelSend *msg) { + +  struct mwService *srvc; + +  srvc = mwChannel_getService(chan); +  incr_stat(chan, mwChannelStat_MSG_RECV, 1); + +  if(msg->head.options & mwMessageOption_ENCRYPT) { +    struct mwOpaque data = { 0, 0 }; +    mwOpaque_clone(&data, &msg->data); + +    mwCipherInstance_decrypt(chan->cipher, &data); +    mwService_recv(srvc, chan, msg->type, &data); +    mwOpaque_clear(&data); +     +  } else { +    mwService_recv(srvc, chan, msg->type, &msg->data); +  } +} + + +static void flush_channel(struct mwChannel *chan) { +  GSList *l; + +  for(l = chan->incoming_queue; l; l = l->next) { +    struct mwMsgChannelSend *msg = (struct mwMsgChannelSend *) l->data; +    l->data = NULL; + +    channel_recv(chan, msg); +    mwMessage_free(MW_MESSAGE(msg)); +  } +  g_slist_free(chan->incoming_queue); +  chan->incoming_queue = NULL; + +  for(l = chan->outgoing_queue; l; l = l->next) { +    struct mwMessage *msg = (struct mwMessage *) l->data; +    l->data = NULL; + +    mwSession_send(chan->session, msg); +    mwMessage_free(msg); +  } +  g_slist_free(chan->outgoing_queue); +  chan->outgoing_queue = NULL; +} + + +void mwChannel_recv(struct mwChannel *chan, struct mwMsgChannelSend *msg) { +  if(chan->state == mwChannel_OPEN) { +    channel_recv(chan, msg); + +  } else { +    queue_incoming(chan, msg); +  } +} + + +struct mwChannel *mwChannel_find(struct mwChannelSet *cs, guint32 chan) { +  g_return_val_if_fail(cs != NULL, NULL); +  g_return_val_if_fail(cs->map != NULL, NULL); +  return g_hash_table_lookup(cs->map, GUINT_TO_POINTER(chan)); +} + + +void mwChannelSet_free(struct mwChannelSet *cs) { +  if(! cs) return; +  if(cs->map) g_hash_table_destroy(cs->map); +  g_free(cs); +} + + +struct mwChannelSet *mwChannelSet_new(struct mwSession *s) { +  struct mwChannelSet *cs = g_new0(struct mwChannelSet, 1); +  cs->session = s; + +  /* for some reason, g_int_hash/g_int_equal cause a SIGSEGV */ +  cs->map = g_hash_table_new_full(g_direct_hash, g_direct_equal, +				  NULL, (GDestroyNotify) channel_free); +  return cs; +} + + +void mwChannel_recvCreate(struct mwChannel *chan, +			  struct mwMsgChannelCreate *msg) { + +  struct mwSession *session; +  GList *list; +  struct mwService *srvc; +   +  g_return_if_fail(chan != NULL); +  g_return_if_fail(msg != NULL); +  g_return_if_fail(chan->id == msg->channel); + +  session = chan->session; +  g_return_if_fail(session != NULL); + +  if(mwChannel_isOutgoing(chan)) { +    g_warning("channel 0x%08x not an incoming channel", chan->id); +    mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); +    return; +  } + +  chan->offered_policy = msg->encrypt.mode; +  g_message("channel offered with encrypt policy 0x%04x", chan->policy); + +  for(list = msg->encrypt.items; list; list = list->next) { +    struct mwEncryptItem *ei = list->data; +    struct mwCipher *cipher; +    struct mwCipherInstance *ci; + +    g_message("channel offered cipher id 0x%04x", ei->id); +    cipher = mwSession_getCipher(session, ei->id); +    if(! cipher) { +      g_message("no such cipher found in session"); +      continue; +    } + +    ci = mwCipher_newInstance(cipher, chan); +    mwCipherInstance_offered(ci, ei); +    mwChannel_addSupportedCipherInstance(chan, ci); +  } + +  mwLoginInfo_clone(&chan->user, &msg->creator); +  chan->service = msg->service; +  chan->proto_type = msg->proto_type; +  chan->proto_ver = msg->proto_ver; +   +  srvc = mwSession_getService(session, msg->service); +  if(srvc) { +    mwService_recvCreate(srvc, chan, msg); + +  } else { +    mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL); +  }   +} + + +void mwChannel_recvAccept(struct mwChannel *chan, +			  struct mwMsgChannelAccept *msg) { + +  struct mwService *srvc; + +  g_return_if_fail(chan != NULL); +  g_return_if_fail(msg != NULL); +  g_return_if_fail(chan->id == msg->head.channel); + +  if(mwChannel_isIncoming(chan)) { +    g_warning("channel 0x%08x not an outgoing channel", chan->id); +    mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); +    return; +  } + +  if(chan->state != mwChannel_WAIT) { +    g_warning("channel 0x%08x state not WAIT: %s", +	      chan->id, state_str(chan->state)); +    mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); +    return; +  } + +  mwLoginInfo_clone(&chan->user, &msg->acceptor); + +  srvc = mwSession_getService(chan->session, chan->service); +  if(! srvc) { +    g_warning("no service: 0x%08x", chan->service); +    mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL); +    return; +  } + +  chan->policy = msg->encrypt.mode; +  g_message("channel accepted with encrypt policy 0x%04x", chan->policy); + +  if(! msg->encrypt.mode || ! msg->encrypt.item) { +    /* no mode or no item means no encryption */ +    mwChannel_selectCipherInstance(chan, NULL); + +  } else { +    guint16 cid = msg->encrypt.item->id; +    struct mwCipherInstance *ci = get_supported(chan, cid); + +    if(! ci) { +      g_warning("not an offered cipher: 0x%04x", cid); +      mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); +      return; +    } + +    mwCipherInstance_accepted(ci, msg->encrypt.item); +    mwChannel_selectCipherInstance(chan, ci); +  } + +  /* mark it as open for the service */ +  state(chan, mwChannel_OPEN, 0); + +  /* let the service know */ +  mwService_recvAccept(srvc, chan, msg); + +  /* flush it if the service didn't just immediately close it */ +  if(mwChannel_isState(chan, mwChannel_OPEN)) { +    channel_open(chan); +  } +} + + +void mwChannel_recvDestroy(struct mwChannel *chan, +			   struct mwMsgChannelDestroy *msg) { + +  struct mwChannelSet *cs; +  struct mwService *srvc; + +  g_return_if_fail(chan != NULL); +  g_return_if_fail(msg != NULL); +  g_return_if_fail(chan->id == msg->head.channel); + +  state(chan, msg->reason? mwChannel_ERROR: mwChannel_DESTROY, msg->reason); + +  srvc = mwChannel_getService(chan); +  if(srvc) mwService_recvDestroy(srvc, chan, msg); + +  cs = mwSession_getChannels(chan->session); +  g_return_if_fail(cs != NULL); +  g_return_if_fail(cs->map != NULL); + +  g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id)); +} + + +void mwChannel_populateSupportedCipherInstances(struct mwChannel *chan) { +  struct mwSession *session; +  GList *list; + +  g_return_if_fail(chan != NULL); + +  session = chan->session; +  g_return_if_fail(session != NULL); + +  for(list = mwSession_getCiphers(session); list; list = list->next) { +    struct mwCipherInstance *ci = mwCipher_newInstance(list->data, chan); +    if(! ci) continue; +    put_supported(chan, ci); +  } +} + + +void mwChannel_addSupportedCipherInstance(struct mwChannel *chan, +					  struct mwCipherInstance *ci) { +  g_return_if_fail(chan != NULL); +  g_message("channel 0x%08x added cipher %s", chan->id, +	    NSTR(mwCipher_getName(mwCipherInstance_getCipher(ci)))); +  put_supported(chan, ci); +} + + +static void collect(gpointer a, gpointer b, gpointer c) { +  GList **list = c; +  *list = g_list_append(*list, b); +} + + +GList *mwChannel_getSupportedCipherInstances(struct mwChannel *chan) { +  GList *list = NULL; + +  g_return_val_if_fail(chan != NULL, NULL); +  g_hash_table_foreach(chan->supported, collect, &list); + +  return list; +} + + +void mwChannel_selectCipherInstance(struct mwChannel *chan, +				    struct mwCipherInstance *ci) { +  struct mwCipher *c; + +  g_return_if_fail(chan != NULL); +  g_return_if_fail(chan->supported != NULL); + +  chan->cipher = ci; +  if(ci) { +    guint cid; + +    c = mwCipherInstance_getCipher(ci); +    cid = mwCipher_getType(c); + +    g_hash_table_steal(chan->supported, GUINT_TO_POINTER(cid)); + +    switch(mwCipher_getType(c)) { +    case mwCipher_RC2_40: +      chan->policy = mwEncrypt_RC2_40; +      break; + +    case mwCipher_RC2_128: +      chan->policy = mwEncrypt_RC2_128; +      break; + +    default: +      /* unsure if this is bad */ +      chan->policy = mwEncrypt_WHATEVER; +    } + +    g_message("channel 0x%08x selected cipher %s", +	      chan->id, NSTR(mwCipher_getName(c))); + +  } else { + +    chan->policy = mwEncrypt_NONE; +    g_message("channel 0x%08x selected no cipher", chan->id); +  } + +  g_hash_table_destroy(chan->supported); +  chan->supported = NULL; +} + + diff --git a/protocols/Sametime/src/meanwhile/src/cipher.c b/protocols/Sametime/src/meanwhile/src/cipher.c new file mode 100644 index 0000000000..8e5bd6f042 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/cipher.c @@ -0,0 +1,982 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <stdlib.h> +#include <time.h> + +#include "mpi/mpi.h" + +#include "mw_channel.h" +#include "mw_cipher.h" +#include "mw_debug.h" +#include "mw_session.h" + + +struct mwMpi { +  mw_mp_int i; +}; + + +/** From RFC2268 */ +static guchar PT[] = { +  0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, +  0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D, +  0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, +  0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, +  0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13, +  0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, +  0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, +  0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82, +  0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, +  0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, +  0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1, +  0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, +  0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, +  0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03, +  0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, +  0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, +  0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7, +  0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, +  0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, +  0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC, +  0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, +  0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, +  0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A, +  0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, +  0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, +  0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9, +  0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, +  0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, +  0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0, +  0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, +  0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, +  0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD +}; + + +/** prime number used in DH exchange */ +static guchar dh_prime[] = { +  0xCF, 0x84, 0xAF, 0xCE, 0x86, 0xDD, 0xFA, 0x52, +  0x7F, 0x13, 0x6D, 0x10, 0x35, 0x75, 0x28, 0xEE, +  0xFB, 0xA0, 0xAF, 0xEF, 0x80, 0x8F, 0x29, 0x17, +  0x4E, 0x3B, 0x6A, 0x9E, 0x97, 0x00, 0x01, 0x71, +  0x7C, 0x8F, 0x10, 0x6C, 0x41, 0xC1, 0x61, 0xA6, +  0xCE, 0x91, 0x05, 0x7B, 0x34, 0xDA, 0x62, 0xCB, +  0xB8, 0x7B, 0xFD, 0xC1, 0xB3, 0x5C, 0x1B, 0x91, +  0x0F, 0xEA, 0x72, 0x24, 0x9D, 0x56, 0x6B, 0x9F +}; + + +/** base used in DH exchange */ +#define DH_BASE  3 + + +struct mwMpi *mwMpi_new() { +  struct mwMpi *i; +  i = g_new0(struct mwMpi, 1); +  mw_mp_init(&i->i); +  return i; +} + + +void mwMpi_free(struct mwMpi *i) { +  if(! i) return; +  mw_mp_clear(&i->i); +  g_free(i); +} + + +static void mwInitDHPrime(mw_mp_int *i) { +  mw_mp_init(i); +  mw_mp_read_unsigned_bin(i, dh_prime, 64); +} + + +void mwMpi_setDHPrime(struct mwMpi *i) { +  g_return_if_fail(i != NULL); +  mw_mp_read_unsigned_bin(&i->i, dh_prime, 64); +} + + +static void mwInitDHBase(mw_mp_int *i) { +  mw_mp_init(i); +  mw_mp_set_int(i, DH_BASE); +} + + +void mwMpi_setDHBase(struct mwMpi *i) { +  g_return_if_fail(i != NULL); +  mw_mp_set_int(&i->i, DH_BASE); +} + + +static void mw_mp_set_rand(mw_mp_int *i, guint bits) { +  size_t len, l; +  guchar *buf; + +  l = len = (bits / 8) + 1; +  buf = g_malloc(len); + +  /// Miranda NG adaptation start - MSVC +  //srand(time(NULL)); +  srand((unsigned int)time(NULL)); +  /// Miranda NG adaptation end + +  while(l--) buf[l] = rand() & 0xff; + +  buf[0] &= (0xff >> (8 - (bits % 8))); + +  mw_mp_read_unsigned_bin(i, buf, len); +  g_free(buf); +} + + +static void mwDHRandKeypair(mw_mp_int *private_key, mw_mp_int *public_key) { +  mw_mp_int prime, base; +  +  mwInitDHPrime(&prime); +  mwInitDHBase(&base); + +  mw_mp_set_rand(private_key, 512); +  mw_mp_exptmod(&base, private_key, &prime, public_key); + +  mw_mp_clear(&prime); +  mw_mp_clear(&base); +} + + +void mwMpi_randDHKeypair(struct mwMpi *private_key, struct mwMpi *public_key) { +  g_return_if_fail(private_key != NULL); +  g_return_if_fail(public_key != NULL); + +  mwDHRandKeypair(&private_key->i, &public_key->i); +} + + +static void mwDHCalculateShared(mw_mp_int *shared_key, mw_mp_int *remote_key, +				mw_mp_int *private_key) { +  mw_mp_int prime; +  +  mwInitDHPrime(&prime); +  mw_mp_exptmod(remote_key, private_key, &prime, shared_key); +  mw_mp_clear(&prime); +} + + +void mwMpi_calculateDHShared(struct mwMpi *shared_key, struct mwMpi *remote_key, +			     struct mwMpi *private_key) { + +  g_return_if_fail(shared_key != NULL); +  g_return_if_fail(remote_key != NULL); +  g_return_if_fail(private_key != NULL); + +  mwDHCalculateShared(&shared_key->i, &remote_key->i, &private_key->i); +} + + +static void mwDHImportKey(mw_mp_int *key, struct mwOpaque *o) { +  mw_mp_read_unsigned_bin(key, o->data, o->len); +} + + +void mwMpi_import(struct mwMpi *i, struct mwOpaque *o) { +  g_return_if_fail(i != NULL); +  g_return_if_fail(o != NULL); + +  mwDHImportKey(&i->i, o); +} + + +static void mwDHExportKey(mw_mp_int *key, struct mwOpaque *o) { +  o->len = mw_mp_unsigned_bin_size(key); +  o->data = g_malloc0(o->len); +  mw_mp_to_unsigned_bin(key, o->data); +} + + +void mwMpi_export(struct mwMpi *i, struct mwOpaque *o) { +  g_return_if_fail(i != NULL); +  g_return_if_fail(o != NULL); +   +  mwDHExportKey(&i->i, o); +} + + +void mwKeyRandom(guchar *key, gsize keylen) { +  g_return_if_fail(key != NULL); + +  /// Miranda NG adaptation start - MSVC +  //srand(time(NULL)); +  srand((unsigned int)time(NULL)); +  /// Miranda NG adaptation end +  while(keylen--) key[keylen] = rand() & 0xff; +} + + +void mwIV_init(guchar *iv) { +  iv[0] = 0x01; +  iv[1] = 0x23; +  iv[2] = 0x45; +  iv[3] = 0x67; +  iv[4] = 0x89; +  iv[5] = 0xab; +  iv[6] = 0xcd; +  iv[7] = 0xef; +} + + +/* This does not seem to produce the same results as normal RC2 key +   expansion would, but it works, so eh. It might be smart to farm +   this out to mozilla or openssl */ +void mwKeyExpand(int *ekey, const guchar *key, gsize keylen) { +  guchar tmp[128]; +  int i, j; + +  g_return_if_fail(keylen > 0); +  g_return_if_fail(key != NULL); + +  if(keylen > 128) keylen = 128; + +  /* fill the first chunk with what key bytes we have */ +  for(i = keylen; i--; tmp[i] = key[i]); +  /* memcpy(tmp, key, keylen); */ + +  /* build the remaining key from the given data */ +  for(i = 0; keylen < 128; i++) { +    tmp[keylen] = PT[ (tmp[keylen - 1] + tmp[i]) & 0xff ]; +    keylen++; +  } + +  tmp[0] = PT[ tmp[0] & 0xff ]; + +  for(i = 0, j = 0; i < 64; i++) { +    ekey[i] = (tmp[j] & 0xff) | (tmp[j+1] << 8); +    j += 2; +  } +} + + +/* normal RC2 encryption given a full 128-byte (as 64 ints) key */ +static void mwEncryptBlock(const int *ekey, guchar *out) { + +  int a, b, c, d; +  int i, j; + +  a = (out[7] << 8) | (out[6] & 0xff); +  b = (out[5] << 8) | (out[4] & 0xff); +  c = (out[3] << 8) | (out[2] & 0xff); +  d = (out[1] << 8) | (out[0] & 0xff); + +  for(i = 0; i < 16; i++) { +    j = i * 4; + +    d += ((c & (a ^ 0xffff)) + (b & a) + ekey[j++]); +    d = (d << 1) | (d >> 15 & 0x0001); + +    c += ((b & (d ^ 0xffff)) + (a & d) + ekey[j++]); +    c = (c << 2) | (c >> 14 & 0x0003); + +    b += ((a & (c ^ 0xffff)) + (d & c) + ekey[j++]); +    b = (b << 3) | (b >> 13 & 0x0007); +     +    a += ((d & (b ^ 0xffff)) + (c & b) + ekey[j++]); +    a = (a << 5) | (a >> 11 & 0x001f); + +    if(i == 4 || i == 10) { +      d += ekey[a & 0x003f]; +      c += ekey[d & 0x003f]; +      b += ekey[c & 0x003f]; +      a += ekey[b & 0x003f]; +    }     +  } + +  *out++ = d & 0xff; +  *out++ = (d >> 8) & 0xff; +  *out++ = c & 0xff; +  *out++ = (c >> 8) & 0xff; +  *out++ = b & 0xff; +  *out++ = (b >> 8) & 0xff; +  *out++ = a & 0xff; +  *out++ = (a >> 8) & 0xff; +} + + +void mwEncryptExpanded(const int *ekey, guchar *iv, +		       struct mwOpaque *in_data, +		       struct mwOpaque *out_data) { + +  guchar *i = in_data->data; +  gsize i_len = in_data->len; + +  guchar *o; +  gsize o_len; + +  /// Miranda NG adaptation start - MSVC +  ///int x, y; +  gsize x; +  int y; +  /// Miranda NG adaptation end + +  /* pad upwards to a multiple of 8 */ +  /* o_len = (i_len & -8) + 8; */ +  o_len = i_len + (8 - (i_len % 8)); +  o = g_malloc(o_len); + +  out_data->data = o; +  out_data->len = o_len; + +  /* figure out the amount of padding */ +  y = o_len - i_len; + +  /* copy in to out, and write padding bytes */ +  for(x = i_len; x--; o[x] = i[x]); +  for(x = i_len; x < o_len; o[x++] = y); +  /* memcpy(o, i, i_len); +     memset(o + i_len, y, y); */ + +  /* encrypt in blocks */ +  for(x = o_len; x > 0; x -= 8) { +    for(y = 8; y--; o[y] ^= iv[y]); +    mwEncryptBlock(ekey, o); +    for(y = 8; y--; iv[y] = o[y]); +    /* memcpy(iv, o, 8); */ +    o += 8; +  } +} + + +void mwEncrypt(const guchar *key, gsize keylen, guchar *iv, +	       struct mwOpaque *in, struct mwOpaque *out) { + +  int ekey[64]; +  mwKeyExpand(ekey, key, keylen); +  mwEncryptExpanded(ekey, iv, in, out); +} + + +static void mwDecryptBlock(const int *ekey, guchar *out) { + +  int a, b, c, d; +  int i, j; + +  a = (out[7] << 8) | (out[6] & 0xff); +  b = (out[5] << 8) | (out[4] & 0xff); +  c = (out[3] << 8) | (out[2] & 0xff); +  d = (out[1] << 8) | (out[0] & 0xff); + +  for(i = 16; i--; ) { +    j = i * 4 + 3; + +    a = (a << 11) | (a >> 5 & 0x07ff); +    a -= ((d & (b ^ 0xffff)) + (c & b) + ekey[j--]); + +    b = (b << 13) | (b >> 3 & 0x1fff); +    b -= ((a & (c ^ 0xffff)) + (d & c) + ekey[j--]); + +    c = (c << 14) | (c >> 2 & 0x3fff); +    c -= ((b & (d ^ 0xffff)) + (a & d) + ekey[j--]); + +    d = (d << 15) | (d >> 1 & 0x7fff); +    d -= ((c & (a ^ 0xffff)) + (b & a) + ekey[j--]); + +    if(i == 5 || i == 11) { +      a -= ekey[b & 0x003f]; +      b -= ekey[c & 0x003f]; +      c -= ekey[d & 0x003f]; +      d -= ekey[a & 0x003f]; +    } +  } + +  *out++ = d & 0xff; +  *out++ = (d >> 8) & 0xff; +  *out++ = c & 0xff; +  *out++ = (c >> 8) & 0xff; +  *out++ = b & 0xff; +  *out++ = (b >> 8) & 0xff; +  *out++ = a & 0xff; +  *out++ = (a >> 8) & 0xff; +} + + +void mwDecryptExpanded(const int *ekey, guchar *iv, +		       struct mwOpaque *in_data, +		       struct mwOpaque *out_data) { + +  guchar *i = in_data->data; +  gsize i_len = in_data->len; + +  guchar *o; +  gsize o_len; + +  int x, y; + +  if(i_len % 8) { +    /* this doesn't check to ensure that in_data->len is a multiple of +       8, which is damn well ought to be. */ +    g_warning("attempting decryption of mis-sized data, %u bytes", +	      (guint) i_len); +  } + +  o = g_malloc(i_len); +  o_len = i_len; +  for(x = i_len; x--; o[x] = i[x]); +  /* memcpy(o, i, i_len); */ + +  out_data->data = o; +  out_data->len = o_len; + +  for(x = o_len; x > 0; x -= 8) { +    /* decrypt a block */ +    mwDecryptBlock(ekey, o); + +    /* modify the initialization vector */ +    for(y = 8; y--; o[y] ^= iv[y]); +    for(y = 8; y--; iv[y] = i[y]); +    /* memcpy(iv, i, 8); */ +    i += 8; +    o += 8; +  } + +  /* shorten the length by the value of the filler in the padding +     bytes */ +  out_data->len -= *(o - 1); +} + + +void mwDecrypt(const guchar *key, gsize keylen, guchar *iv, +	       struct mwOpaque *in, struct mwOpaque *out) { + +  int ekey[64]; +  mwKeyExpand(ekey, key, keylen); +  mwDecryptExpanded(ekey, iv, in, out); +} + + + +struct mwCipher_RC2_40 { +  struct mwCipher cipher; +  int session_key[64]; +  gboolean ready; +}; + + +struct mwCipherInstance_RC2_40 { +  struct mwCipherInstance instance; +  int incoming_key[64]; +  guchar outgoing_iv[8]; +  guchar incoming_iv[8]; +}; + + +static const char *get_name_RC2_40() { +  return "RC2/40 Cipher"; +} + + +static const char *get_desc_RC2_40() { +  return "RC2, 40-bit effective key"; +} + + +static int encrypt_RC2_40(struct mwCipherInstance *ci, +			  struct mwOpaque *data) { + +  struct mwCipherInstance_RC2_40 *cir; +  struct mwCipher_RC2_40 *cr; +  struct mwOpaque o = { 0, 0 }; + +  cir = (struct mwCipherInstance_RC2_40 *) ci; +  cr = (struct mwCipher_RC2_40 *) ci->cipher; + +  mwEncryptExpanded(cr->session_key, cir->outgoing_iv, data, &o); + +  mwOpaque_clear(data); +  data->data = o.data; +  data->len = o.len; + +  return 0; +} + + +static int decrypt_RC2_40(struct mwCipherInstance *ci, +			  struct mwOpaque *data) { +   +  struct mwCipherInstance_RC2_40 *cir; +  struct mwCipher_RC2_40 *cr; +  struct mwOpaque o = { 0, 0 }; + +  cir = (struct mwCipherInstance_RC2_40 *) ci; +  cr = (struct mwCipher_RC2_40 *) ci->cipher; + +  mwDecryptExpanded(cir->incoming_key, cir->incoming_iv, data, &o); + +  mwOpaque_clear(data); +  data->data = o.data; +  data->len = o.len; + +  return 0; +} + + +static struct mwCipherInstance * +new_instance_RC2_40(struct mwCipher *cipher, +		    struct mwChannel *chan) { + +  struct mwCipher_RC2_40 *cr; +  struct mwCipherInstance_RC2_40 *cir; +  struct mwCipherInstance *ci; + +  cr = (struct mwCipher_RC2_40 *) cipher; + +  /* a bit of lazy initialization here */ +  if(! cr->ready) { +    struct mwLoginInfo *info = mwSession_getLoginInfo(cipher->session); +    mwKeyExpand(cr->session_key, (guchar *) info->login_id, 5); +    cr->ready = TRUE; +  } + +  cir = g_new0(struct mwCipherInstance_RC2_40, 1); +  ci = &cir->instance; + +  ci->cipher = cipher; +  ci->channel = chan; + +  mwIV_init(cir->incoming_iv); +  mwIV_init(cir->outgoing_iv); + +  return ci; +} + + +static struct mwEncryptItem *new_item_RC2_40(struct mwCipherInstance *ci) { +  struct mwEncryptItem *e; + +  e = g_new0(struct mwEncryptItem, 1); +  e->id = mwCipher_RC2_40; +  return e; +} + + +static struct mwEncryptItem * +offer_RC2_40(struct mwCipherInstance *ci) { +  return new_item_RC2_40(ci); +} + + +static void accepted_RC2_40(struct mwCipherInstance *ci, +			    struct mwEncryptItem *item) { + +  struct mwCipherInstance_RC2_40 *cir; +  struct mwLoginInfo *info; + +  cir = (struct mwCipherInstance_RC2_40 *) ci; +  info = mwChannel_getUser(ci->channel); + +  if(info->login_id) { +    mwKeyExpand(cir->incoming_key, (guchar *) info->login_id, 5); +  } +} + + +static struct mwEncryptItem * +accept_RC2_40(struct mwCipherInstance *ci) { + +  accepted_RC2_40(ci, NULL); +  return new_item_RC2_40(ci); +} + + +struct mwCipher *mwCipher_new_RC2_40(struct mwSession *s) { +  struct mwCipher_RC2_40 *cr = g_new0(struct mwCipher_RC2_40, 1); +  struct mwCipher *c = &cr->cipher; + +  c->session = s; +  c->type = mwCipher_RC2_40; +  c->get_name = get_name_RC2_40; +  c->get_desc = get_desc_RC2_40; +  c->new_instance = new_instance_RC2_40; + +  c->offer = offer_RC2_40; + +  c->accepted = accepted_RC2_40; +  c->accept = accept_RC2_40; + +  c->encrypt = encrypt_RC2_40; +  c->decrypt = decrypt_RC2_40; + +  return c; +} + + +struct mwCipher_RC2_128 { +  struct mwCipher cipher; +  mw_mp_int private_key; +  struct mwOpaque public_key; +}; + + +struct mwCipherInstance_RC2_128 { +  struct mwCipherInstance instance; +  int shared[64];      /* shared secret determined via DH exchange */ +  guchar outgoing_iv[8]; +  guchar incoming_iv[8]; +}; + + +static const char *get_name_RC2_128() { +  return "RC2/128 Cipher"; +} + + +static const char *get_desc_RC2_128() { +  return "RC2, DH shared secret key"; +} + + +static struct mwCipherInstance * +new_instance_RC2_128(struct mwCipher *cipher, +		     struct mwChannel *chan) { + +  struct mwCipher_RC2_128 *cr; +  struct mwCipherInstance_RC2_128 *cir; +  struct mwCipherInstance *ci; + +  cr = (struct mwCipher_RC2_128 *) cipher; + +  cir = g_new0(struct mwCipherInstance_RC2_128, 1); +  ci = &cir->instance; +   +  ci->cipher = cipher; +  ci->channel = chan; + +  mwIV_init(cir->incoming_iv); +  mwIV_init(cir->outgoing_iv); + +  return ci; +} + + +static void offered_RC2_128(struct mwCipherInstance *ci, +			    struct mwEncryptItem *item) { +   +  mw_mp_int remote_key; +  mw_mp_int shared; +  struct mwOpaque sho = { 0, 0 }; + +  struct mwCipher *c; +  struct mwCipher_RC2_128 *cr; +  struct mwCipherInstance_RC2_128 *cir; + +  c = ci->cipher; +  cr = (struct mwCipher_RC2_128 *) c; +  cir = (struct mwCipherInstance_RC2_128 *) ci; + +  mw_mp_init(&remote_key); +  mw_mp_init(&shared); + +  mwDHImportKey(&remote_key, &item->info); +  mwDHCalculateShared(&shared, &remote_key, &cr->private_key); +  mwDHExportKey(&shared, &sho); + +  /* key expanded from the last 16 bytes of the DH shared secret. This +     took me forever to figure out. 16 bytes is 128 bit. */ +  /* the sh_len-16 is important, because the key len could +     hypothetically start with 8bits or more unset, meaning the +     exported key might be less than 64 bytes in length */ +  mwKeyExpand(cir->shared, sho.data+(sho.len-16), 16); +   +  mw_mp_clear(&remote_key); +  mw_mp_clear(&shared); +  mwOpaque_clear(&sho); +} + + +static struct mwEncryptItem * +offer_RC2_128(struct mwCipherInstance *ci) { + +  struct mwCipher *c; +  struct mwCipher_RC2_128 *cr; +  struct mwEncryptItem *ei; + +  c = ci->cipher; +  cr = (struct mwCipher_RC2_128 *) c; + +  ei = g_new0(struct mwEncryptItem, 1); +  ei->id = mwCipher_RC2_128; +  mwOpaque_clone(&ei->info, &cr->public_key); + +  return ei; +}			   + + +static void accepted_RC2_128(struct mwCipherInstance *ci, +			     struct mwEncryptItem *item) { + +  /// Miranda NG adaptation start - MSVC +  ///return offered_RC2_128(ci, item); +  offered_RC2_128(ci, item); +  /// Miranda NG adaptation end +} + + +static struct mwEncryptItem * +accept_RC2_128(struct mwCipherInstance *ci) { + +  return offer_RC2_128(ci); +} + + +static int encrypt_RC2_128(struct mwCipherInstance *ci, +			   struct mwOpaque *data) { + +  struct mwCipherInstance_RC2_128 *cir; +  struct mwOpaque o = { 0, 0 }; + +  cir = (struct mwCipherInstance_RC2_128 *) ci; + +  mwEncryptExpanded(cir->shared, cir->outgoing_iv, data, &o); + +  mwOpaque_clear(data); +  data->data = o.data; +  data->len = o.len; + +  return 0; +} + + +static int decrypt_RC2_128(struct mwCipherInstance *ci, +			   struct mwOpaque *data) { + +  struct mwCipherInstance_RC2_128 *cir; +  struct mwOpaque o = { 0, 0 }; + +  cir = (struct mwCipherInstance_RC2_128 *) ci; + +  mwDecryptExpanded(cir->shared, cir->incoming_iv, data, &o); + +  mwOpaque_clear(data); +  data->data = o.data; +  data->len = o.len; + +  return 0; +} + + +static void clear_RC2_128(struct mwCipher *c) { +  struct mwCipher_RC2_128 *cr; +  cr = (struct mwCipher_RC2_128 *) c; + +  mw_mp_clear(&cr->private_key); +  mwOpaque_clear(&cr->public_key); +} + + +struct mwCipher *mwCipher_new_RC2_128(struct mwSession *s) { +  struct mwCipher_RC2_128 *cr; +  struct mwCipher *c; + +  mw_mp_int pubkey; + +  cr = g_new0(struct mwCipher_RC2_128, 1); +  c = &cr->cipher; + +  c->session = s; +  c->type = mwCipher_RC2_128; +  c->get_name = get_name_RC2_128; +  c->get_desc = get_desc_RC2_128; +  c->new_instance = new_instance_RC2_128; + +  c->offered = offered_RC2_128; +  c->offer = offer_RC2_128; + +  c->accepted = accepted_RC2_128; +  c->accept = accept_RC2_128; + +  c->encrypt = encrypt_RC2_128; +  c->decrypt = decrypt_RC2_128; + +  c->clear = clear_RC2_128; +   +  mw_mp_init(&cr->private_key); +  mw_mp_init(&pubkey); +  mwDHRandKeypair(&cr->private_key, &pubkey); +  mwDHExportKey(&pubkey, &cr->public_key); +  mw_mp_clear(&pubkey); + +  return c; +} + + +struct mwSession *mwCipher_getSession(struct mwCipher *cipher) { +  g_return_val_if_fail(cipher != NULL, NULL); +  return cipher->session; +} + + +guint16 mwCipher_getType(struct mwCipher *cipher) { +  /* oh man, this is a bad failover... who the hell decided to make +     zero a real cipher id? */ +  g_return_val_if_fail(cipher != NULL, 0xffff); +  return cipher->type; +} + + +const char *mwCipher_getName(struct mwCipher *cipher) { +  g_return_val_if_fail(cipher != NULL, NULL); +  g_return_val_if_fail(cipher->get_name != NULL, NULL); +  return cipher->get_name(); +} + + +const char *mwCipher_getDesc(struct mwCipher *cipher) { +  g_return_val_if_fail(cipher != NULL, NULL); +  g_return_val_if_fail(cipher->get_desc != NULL, NULL); +  return cipher->get_desc(); +} + + +void mwCipher_free(struct mwCipher *cipher) { +  if(! cipher) return; + +  if(cipher->clear) +    cipher->clear(cipher); + +  g_free(cipher); +} + + +struct mwCipherInstance *mwCipher_newInstance(struct mwCipher *cipher, +					      struct mwChannel *chan) { +  g_return_val_if_fail(cipher != NULL, NULL); +  g_return_val_if_fail(chan != NULL, NULL); +  g_return_val_if_fail(cipher->new_instance != NULL, NULL); +  return cipher->new_instance(cipher, chan); +} + + +struct mwCipher *mwCipherInstance_getCipher(struct mwCipherInstance *ci) { +  g_return_val_if_fail(ci != NULL, NULL); +  return ci->cipher; +} + + +struct mwChannel *mwCipherInstance_getChannel(struct mwCipherInstance *ci) { +  g_return_val_if_fail(ci != NULL, NULL); +  return ci->channel; +} + + +void mwCipherInstance_offered(struct mwCipherInstance *ci, +			      struct mwEncryptItem *item) { +  struct mwCipher *cipher; + +  g_return_if_fail(ci != NULL); + +  cipher = ci->cipher; +  g_return_if_fail(cipher != NULL); + +  if(cipher->offered) cipher->offered(ci, item); +} + + +struct mwEncryptItem * +mwCipherInstance_offer(struct mwCipherInstance *ci) { +  struct mwCipher *cipher; + +  g_return_val_if_fail(ci != NULL, NULL); + +  cipher = ci->cipher; +  g_return_val_if_fail(cipher != NULL, NULL); + +  return cipher->offer(ci); +} + + +void mwCipherInstance_accepted(struct mwCipherInstance *ci, +			       struct mwEncryptItem *item) { +  struct mwCipher *cipher; + +  g_return_if_fail(ci != NULL); + +  cipher = ci->cipher; +  g_return_if_fail(cipher != NULL); + +  if(cipher->accepted) cipher->accepted(ci, item); +} + + +struct mwEncryptItem * +mwCipherInstance_accept(struct mwCipherInstance *ci) { +  struct mwCipher *cipher; + +  g_return_val_if_fail(ci != NULL, NULL); + +  cipher = ci->cipher; +  g_return_val_if_fail(cipher != NULL, NULL); + +  return cipher->accept(ci); +} + + +int mwCipherInstance_encrypt(struct mwCipherInstance *ci, +			     struct mwOpaque *data) { +  struct mwCipher *cipher; + +  g_return_val_if_fail(data != NULL, 0); + +  if(! ci) return 0; +  cipher = ci->cipher; + +  g_return_val_if_fail(cipher != NULL, -1); + +  return (cipher->encrypt)? +    cipher->encrypt(ci, data): 0; +} + + +int mwCipherInstance_decrypt(struct mwCipherInstance *ci, +			     struct mwOpaque *data) { +  struct mwCipher *cipher; + +  g_return_val_if_fail(data != NULL, 0); + +  if(! ci) return 0; +  cipher = ci->cipher; + +  g_return_val_if_fail(cipher != NULL, -1); + +  return (cipher->decrypt)? +    cipher->decrypt(ci, data): 0; +} + + +void mwCipherInstance_free(struct mwCipherInstance *ci) { +  struct mwCipher *cipher; + +  if(! ci) return; + +  cipher = ci->cipher; + +  if(cipher && cipher->clear_instance) +    cipher->clear_instance(ci); + +  g_free(ci); +} + diff --git a/protocols/Sametime/src/meanwhile/src/common.c b/protocols/Sametime/src/meanwhile/src/common.c new file mode 100644 index 0000000000..555edd2c1c --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/common.c @@ -0,0 +1,947 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <glib.h> +#include <string.h> + +#include "mw_common.h" + + +/** @todo the *_get functions should make sure to clear their +    structures in the event of failure, to prevent memory leaks */ + + +#define MW16_PUT(b, val) \ +  *(b)++ = ((val) >> 0x08) & 0xff; \ +  *(b)++ = (val) & 0xff; + + +#define MW16_GET(b, val) \ +  val = (*(b)++ & 0xff) << 8; \ +  val = val | (*(b)++ & 0xff); + + +#define MW32_PUT(b, val) \ +  *(b)++ = ((val) >> 0x18) & 0xff; \ +  *(b)++ = ((val) >> 0x10) & 0xff; \ +  *(b)++ = ((val) >> 0x08) & 0xff; \ +  *(b)++ = (val) & 0xff; + + +#define MW32_GET(b, val) \ +  val = (*(b)++ & 0xff) << 0x18; \ +  val = val | (*(b)++ & 0xff) << 0x10; \ +  val = val | (*(b)++ & 0xff) << 0x08; \ +  val = val | (*(b)++ & 0xff); + + +struct mwPutBuffer { +  guchar *buf;  /**< head of buffer */ +  gsize len;    /**< length of buffer */ + +  guchar *ptr;  /**< offset to first unused byte */ +  gsize rem;    /**< count of unused bytes remaining */ +}; + + +struct mwGetBuffer { +  guchar *buf;  /**< head of buffer */ +  gsize len;    /**< length of buffer */ + +  guchar *ptr;  /**< offset to first unused byte */ +  gsize rem;    /**< count of unused bytes remaining */ + +  gboolean wrap;   /**< TRUE to indicate buf shouldn't be freed */ +  gboolean error;  /**< TRUE to indicate an error */ +}; + + +#define BUFFER_USED(buffer) \ +  ((buffer)->len - (buffer)->rem) + + +/** ensure that there's at least enough space remaining in the put +    buffer to fit needed. */ +static void ensure_buffer(struct mwPutBuffer *b, gsize needed) { +  if(b->rem < needed) { +    gsize len = b->len, use = BUFFER_USED(b); +    guchar *buf; + +    /* newly created buffers are empty until written to, and then they +       have 1024 available */ +    if(! len) len = 1024; + +    /* double len until it's large enough to fit needed */ +    while( (len - use) < needed ) len = len << 1; + +    /* create the new buffer. if there was anything in the old buffer, +       copy it into the new buffer and free the old copy */ +    buf = g_malloc(len); +    if(b->buf) { +      memcpy(buf, b->buf, use); +      g_free(b->buf); +    } + +    /* put the new buffer into b */ +    b->buf = buf; +    b->len = len; +    b->ptr = buf + use; +    b->rem = len - use; +  } +} + + +/** determine if there are at least needed bytes available in the +    buffer. sets the error flag if there's not at least needed bytes +    left in the buffer + +    @returns true if there's enough data, false if not */ +static gboolean check_buffer(struct mwGetBuffer *b, gsize needed) { +  if(! b->error)  b->error = (b->rem < needed); +  return ! b->error; +} + + +struct mwPutBuffer *mwPutBuffer_new() { +  return g_new0(struct mwPutBuffer, 1); +} + + +void mwPutBuffer_write(struct mwPutBuffer *b, gpointer data, gsize len) { +  g_return_if_fail(b != NULL); +  g_return_if_fail(data != NULL); + +  if(! len) return; + +  ensure_buffer(b, len); +  memcpy(b->ptr, data, len); +  b->ptr += len; +  b->rem -= len; +} + + +void mwPutBuffer_free(struct mwPutBuffer *b) { +  if(! b) return; +  g_free(b->buf); +  g_free(b); +} + + +void mwPutBuffer_finalize(struct mwOpaque *to, struct mwPutBuffer *from) { +  g_return_if_fail(to != NULL); +  g_return_if_fail(from != NULL); + +  to->len = BUFFER_USED(from); +  to->data = from->buf; + +  g_free(from); +} + + +struct mwGetBuffer *mwGetBuffer_new(struct mwOpaque *o) { +  struct mwGetBuffer *b = g_new0(struct mwGetBuffer, 1); + +  if(o && o->len) { +    b->buf = b->ptr = g_memdup(o->data, o->len); +    b->len = b->rem = o->len; +  } + +  return b; +} + + +struct mwGetBuffer *mwGetBuffer_wrap(const struct mwOpaque *o) { +  struct mwGetBuffer *b = g_new0(struct mwGetBuffer, 1); + +  if(o && o->len) { +    b->buf = b->ptr = o->data; +    b->len = b->rem = o->len; +  } +  b->wrap = TRUE; + +  return b; +} + + +gsize mwGetBuffer_read(struct mwGetBuffer *b, gpointer data, gsize len) { +  g_return_val_if_fail(b != NULL, 0); +  g_return_val_if_fail(data != NULL, 0); + +  if(b->error) return 0; +  if(! len) return 0; + +  if(b->rem < len) +    len = b->rem; + +  memcpy(data, b->ptr, len); +  b->ptr += len; +  b->rem -= len; + +  return len; +} + + +gsize mwGetBuffer_advance(struct mwGetBuffer *b, gsize len) { +  g_return_val_if_fail(b != NULL, 0); + +  if(b->error) return 0; +  if(! len) return 0; + +  if(b->rem < len) +    len = b->rem; + +  b->ptr += len; +  b->rem -= len; + +  return len; +} + + +void mwGetBuffer_reset(struct mwGetBuffer *b) { +  g_return_if_fail(b != NULL); + +  b->rem = b->len; +  b->ptr = b->buf; +  b->error = FALSE; +} + + +gsize mwGetBuffer_remaining(struct mwGetBuffer *b) { +  g_return_val_if_fail(b != NULL, 0); +  return b->rem; +} + + +gboolean mwGetBuffer_error(struct mwGetBuffer *b) { +  g_return_val_if_fail(b != NULL, TRUE); +  return b->error; +} + + +void mwGetBuffer_free(struct mwGetBuffer *b) { +  if(! b) return; +  if(! b->wrap) g_free(b->buf); +  g_free(b); +} + + +#define guint16_buflen()  2 + + +void guint16_put(struct mwPutBuffer *b, guint16 val) { +  g_return_if_fail(b != NULL); + +  ensure_buffer(b, guint16_buflen()); +  MW16_PUT(b->ptr, val); +  b->rem -= guint16_buflen(); +} + + +void guint16_get(struct mwGetBuffer *b, guint16 *val) { +  g_return_if_fail(b != NULL); + +  if(b->error) return; +  g_return_if_fail(check_buffer(b, guint16_buflen())); + +  MW16_GET(b->ptr, *val); +  b->rem -= guint16_buflen(); +} + + +guint16 guint16_peek(struct mwGetBuffer *b) { +  guchar *buf = b->buf; +  guint16 r = 0; +   +  if(b->rem >= guint16_buflen()) +    MW16_GET(buf, r); + +  return r; +} + + +#define guint32_buflen()  4 + + +void guint32_put(struct mwPutBuffer *b, guint32 val) { +  g_return_if_fail(b != NULL); + +  ensure_buffer(b, guint32_buflen()); +  MW32_PUT(b->ptr, val); +  b->rem -= guint32_buflen(); +} + + +void guint32_get(struct mwGetBuffer *b, guint32 *val) { +  g_return_if_fail(b != NULL); + +  if(b->error) return; +  g_return_if_fail(check_buffer(b, guint32_buflen())); + +  MW32_GET(b->ptr, *val); +  b->rem -= guint32_buflen(); +} + + +guint32 guint32_peek(struct mwGetBuffer *b) { +  guchar *buf = b->buf; +  guint32 r = 0; + +  if(b->rem >= guint32_buflen()) +    MW32_GET(buf, r); + +  return r; +} + + +#define gboolean_buflen()  1 + + +void gboolean_put(struct mwPutBuffer *b, gboolean val) { +  g_return_if_fail(b != NULL); + +  ensure_buffer(b, gboolean_buflen()); +  *(b->ptr) = !! val; +  b->ptr++; +  b->rem--; +} + + +void gboolean_get(struct mwGetBuffer *b, gboolean *val) { +  g_return_if_fail(b != NULL); + +  if(b->error) return; +  g_return_if_fail(check_buffer(b, gboolean_buflen())); + +  *val = !! *(b->ptr); +  b->ptr++; +  b->rem--; +} + + +gboolean gboolean_peek(struct mwGetBuffer *b) { +  gboolean v = FALSE; + +  if(b->rem >= gboolean_buflen()) +    v = !! *(b->ptr); + +  return v; +} + + +static gboolean mw_streq(const char *a, const char *b) { +  return (a == b) || (a && b && !strcmp(a, b)); +} + + +void mwString_put(struct mwPutBuffer *b, const char *val) { +  gsize len = 0; + +  g_return_if_fail(b != NULL); + +  if(val) len = strlen(val); + +  guint16_put(b, (guint16) len); + +  if(len) { +    ensure_buffer(b, len); +    memcpy(b->ptr, val, len); +    b->ptr += len; +    b->rem -= len; +  } +} + + +void mwString_get(struct mwGetBuffer *b, char **val) { +  guint16 len = 0; + +  g_return_if_fail(b != NULL); +  g_return_if_fail(val != NULL); + +  *val = NULL; + +  if(b->error) return; +  guint16_get(b, &len); + +  g_return_if_fail(check_buffer(b, (gsize) len)); + +  if(len) { +    *val = g_malloc0(len + 1); +    memcpy(*val, b->ptr, len); +    b->ptr += len; +    b->rem -= len; +  } +} + + +void mwOpaque_put(struct mwPutBuffer *b, const struct mwOpaque *o) { +  gsize len; + +  g_return_if_fail(b != NULL); + +  if(! o) { +    guint32_put(b, 0x00); +    return; +  } + +  len = o->len; +  if(len) +    g_return_if_fail(o->data != NULL); +   +  guint32_put(b, (guint32) len); + +  if(len) { +    ensure_buffer(b, len); +    memcpy(b->ptr, o->data, len); +    b->ptr += len; +    b->rem -= len; +  } +} + + +void mwOpaque_get(struct mwGetBuffer *b, struct mwOpaque *o) { +  guint32 tmp = 0; + +  g_return_if_fail(b != NULL); +  g_return_if_fail(o != NULL); + +  o->len = 0; +  o->data = NULL; +   +  if(b->error) return; +  guint32_get(b, &tmp); + +  g_return_if_fail(check_buffer(b, (gsize) tmp)); + +  o->len = (gsize) tmp; +  if(tmp > 0) { +    o->data = g_memdup(b->ptr, tmp); +    b->ptr += tmp; +    b->rem -= tmp; +  } +} + + +void mwOpaque_clear(struct mwOpaque *o) { +  if(! o) return; +  g_free(o->data); +  o->data = NULL; +  o->len = 0; +} + + +void mwOpaque_free(struct mwOpaque *o) { +  if(! o) return; +  g_free(o->data); +  g_free(o); +} + + +void mwOpaque_clone(struct mwOpaque *to, const struct mwOpaque *from) { +  g_return_if_fail(to != NULL); + +  to->len = 0; +  to->data = NULL; + +  if(from) { +    to->len = from->len; +    if(to->len) +      to->data = g_memdup(from->data, to->len); +  } +} + + +/* 8.2 Common Structures */ +/* 8.2.1 Login Info block */ + + +void mwLoginInfo_put(struct mwPutBuffer *b, const struct mwLoginInfo *login) { +  g_return_if_fail(b != NULL); +  g_return_if_fail(login != NULL); + +  mwString_put(b, login->login_id); +  guint16_put(b, login->type); +  mwString_put(b, login->user_id); +  mwString_put(b, login->user_name); +  mwString_put(b, login->community); +  gboolean_put(b, login->full); + +  if(login->full) { +    mwString_put(b, login->desc); +    guint32_put(b, login->ip_addr); +    mwString_put(b, login->server_id); +  } +} + + +void mwLoginInfo_get(struct mwGetBuffer *b, struct mwLoginInfo *login) { +  g_return_if_fail(b != NULL); +  g_return_if_fail(login != NULL); + +  if(b->error) return; + +  mwString_get(b, &login->login_id); +  guint16_get(b, &login->type); +  mwString_get(b, &login->user_id); +  mwString_get(b, &login->user_name); +  mwString_get(b, &login->community); +  gboolean_get(b, &login->full); +   +  if(login->full) { +    mwString_get(b, &login->desc); +    guint32_get(b, &login->ip_addr); +    mwString_get(b, &login->server_id); +  } +} + + +void mwLoginInfo_clear(struct mwLoginInfo *login) { +  if(! login) return; + +  g_free(login->login_id); +  g_free(login->user_id); +  g_free(login->user_name); +  g_free(login->community); +  g_free(login->desc); +  g_free(login->server_id); + +  memset(login, 0x00, sizeof(struct mwLoginInfo)); +} + + +void mwLoginInfo_clone(struct mwLoginInfo *to, +		       const struct mwLoginInfo *from) { + +  g_return_if_fail(to != NULL); +  g_return_if_fail(from != NULL); + +  to->login_id= g_strdup(from->login_id); +  to->type = from->type; +  to->user_id = g_strdup(from->user_id); +  to->user_name = g_strdup(from->user_name); +  to->community = g_strdup(from->community); + +  if( (to->full = from->full) ) { +    to->desc = g_strdup(from->desc); +    to->ip_addr = from->ip_addr; +    to->server_id = g_strdup(from->server_id); +  } +} + + +/* 8.2.2 Private Info Block */ + + +void mwUserItem_put(struct mwPutBuffer *b, const struct mwUserItem *user) { +  g_return_if_fail(b != NULL); +  g_return_if_fail(user != NULL); + +  gboolean_put(b, user->full); +  mwString_put(b, user->id); +  mwString_put(b, user->community); +   +  if(user->full) +    mwString_put(b, user->name); +} + + +void mwUserItem_get(struct mwGetBuffer *b, struct mwUserItem *user) { +  g_return_if_fail(b != NULL); +  g_return_if_fail(user != NULL); + +  if(b->error) return; + +  gboolean_get(b, &user->full); +  mwString_get(b, &user->id); +  mwString_get(b, &user->community); + +  if(user->full) +    mwString_get(b, &user->name); +} + + +void mwUserItem_clear(struct mwUserItem *user) { +  if(! user) return; + +  g_free(user->id); +  g_free(user->community); +  g_free(user->name); + +  memset(user, 0x00, sizeof(struct mwUserItem)); +} + + +void mwUserItem_clone(struct mwUserItem *to, +		      const struct mwUserItem *from) { + +  g_return_if_fail(to != NULL); +  g_return_if_fail(from != NULL); + +  to->full = from->full; +  to->id = g_strdup(from->id); +  to->community = g_strdup(from->community); +  to->name = (to->full)? g_strdup(from->name): NULL; +} + + +void mwPrivacyInfo_put(struct mwPutBuffer *b, +		       const struct mwPrivacyInfo *info) { +  guint32 c; + +  g_return_if_fail(b != NULL); +  g_return_if_fail(info != NULL); + +  gboolean_put(b, info->deny); +  guint32_put(b, info->count); + +  for(c = info->count; c--; ) mwUserItem_put(b, info->users + c); +} + + +void mwPrivacyInfo_get(struct mwGetBuffer *b, struct mwPrivacyInfo *info) { +  g_return_if_fail(b != NULL); +  g_return_if_fail(info != NULL); + +  if(b->error) return; + +  gboolean_get(b, &info->deny); +  guint32_get(b, &info->count); + +  if(info->count) { +    guint32 c = info->count; +    info->users = g_new0(struct mwUserItem, c); +    while(c--) mwUserItem_get(b, info->users + c); +  } +} + + +void mwPrivacyInfo_clone(struct mwPrivacyInfo *to, +			 const struct mwPrivacyInfo *from) { + +  guint32 c; + +  g_return_if_fail(to != NULL); +  g_return_if_fail(from != NULL); + +  to->deny = from->deny; +  c = to->count = from->count; + +  to->users = g_new0(struct mwUserItem, c); +  while(c--) mwUserItem_clone(to->users+c, from->users+c); +} + + +void mwPrivacyInfo_clear(struct mwPrivacyInfo *info) { +  struct mwUserItem *u; +  guint32 c; + +  g_return_if_fail(info != NULL); + +  u = info->users; +  c = info->count; + +  while(c--) mwUserItem_clear(u + c); +  g_free(u); + +  info->count = 0; +  info->users = NULL; +} + + +/* 8.2.3 User Status Block */ + + +void mwUserStatus_put(struct mwPutBuffer *b, +		      const struct mwUserStatus *stat) { + +  g_return_if_fail(b != NULL); +  g_return_if_fail(stat != NULL); + +  guint16_put(b, stat->status); +  guint32_put(b, stat->time); +  mwString_put(b, stat->desc); +} + + +void mwUserStatus_get(struct mwGetBuffer *b, struct mwUserStatus *stat) { +  g_return_if_fail(b != NULL); +  g_return_if_fail(stat != NULL); + +  if(b->error) return; + +  guint16_get(b, &stat->status); +  guint32_get(b, &stat->time); +  mwString_get(b, &stat->desc); + +  /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/status_timestamp_workaround.diff +  // Quick'n ugly hack for recent Sametime clients +  stat->time = 0; +  /// Miranda NG adaptation - end +} + + +void mwUserStatus_clear(struct mwUserStatus *stat) { +  if(! stat) return; +  g_free(stat->desc); +  memset(stat, 0x00, sizeof(struct mwUserStatus)); +} + + +void mwUserStatus_clone(struct mwUserStatus *to, +			const struct mwUserStatus *from) { + +  g_return_if_fail(to != NULL); +  g_return_if_fail(from != NULL); + +  to->status = from->status; +  to->time = from->time; +  to->desc = g_strdup(from->desc); +} + + +/* 8.2.4 ID Block */ + + +void mwIdBlock_put(struct mwPutBuffer *b, const struct mwIdBlock *id) { +  g_return_if_fail(b != NULL); +  g_return_if_fail(id != NULL); + +  mwString_put(b, id->user); +  mwString_put(b, id->community); +} + + +void mwIdBlock_get(struct mwGetBuffer *b, struct mwIdBlock *id) { +  g_return_if_fail(b != NULL); +  g_return_if_fail(id != NULL); + +  if(b->error) return; + +  mwString_get(b, &id->user); +  mwString_get(b, &id->community); +} + + +void mwIdBlock_clear(struct mwIdBlock *id) { +  if(! id) return; + +  g_free(id->user); +  id->user = NULL; + +  g_free(id->community); +  id->community = NULL; +} + + +void mwIdBlock_clone(struct mwIdBlock *to, const struct mwIdBlock *from) { +  g_return_if_fail(to != NULL); +  g_return_if_fail(from != NULL); + +  to->user = g_strdup(from->user); +  to->community = g_strdup(from->community); +} + + +guint mwIdBlock_hash(const struct mwIdBlock *idb) { +  return (idb)? g_str_hash(idb->user): 0; +} + + +gboolean mwIdBlock_equal(const struct mwIdBlock *a, +			 const struct mwIdBlock *b) { + +  g_return_val_if_fail(a != NULL, FALSE); +  g_return_val_if_fail(b != NULL, FALSE); + +  return ( mw_streq(a->user, b->user) && +	   mw_streq(a->community, b->community) ); +} + + +/* 8.2.5 Encryption Block */ + +/** @todo I think this can be put into cipher */ + +void mwEncryptItem_put(struct mwPutBuffer *b, +		       const struct mwEncryptItem *ei) { + +  g_return_if_fail(b != NULL); +  g_return_if_fail(ei != NULL); +   +  guint16_put(b, ei->id); +  mwOpaque_put(b, &ei->info); + +} + + +void mwEncryptItem_get(struct mwGetBuffer *b, struct mwEncryptItem *ei) { +  g_return_if_fail(b != NULL); +  g_return_if_fail(ei != NULL); + +  if(b->error) return; + +  guint16_get(b, &ei->id); +  mwOpaque_get(b, &ei->info); +} + + +void mwEncryptItem_clear(struct mwEncryptItem *ei) { +  if(! ei) return; +  ei->id = 0x0000; +  mwOpaque_clear(&ei->info); +} + + +void mwEncryptItem_free(struct mwEncryptItem *ei) { +  mwEncryptItem_clear(ei); +  g_free(ei); +} + + +/* 8.4.2.1 Awareness ID Block */ + + +/** @todo move this into srvc_aware */ + +void mwAwareIdBlock_put(struct mwPutBuffer *b, +			const struct mwAwareIdBlock *idb) { + +  g_return_if_fail(b != NULL); +  g_return_if_fail(idb != NULL); + +  guint16_put(b, idb->type); +  mwString_put(b, idb->user); +  mwString_put(b, idb->community); +} + + +void mwAwareIdBlock_get(struct mwGetBuffer *b, struct mwAwareIdBlock *idb) { +  g_return_if_fail(b != NULL); +  g_return_if_fail(idb != NULL); + +  if(b->error) return; + +  guint16_get(b, &idb->type); +  mwString_get(b, &idb->user); +  mwString_get(b, &idb->community); +} + + +void mwAwareIdBlock_clone(struct mwAwareIdBlock *to, +			  const struct mwAwareIdBlock *from) { + +  g_return_if_fail(to != NULL); +  g_return_if_fail(from != NULL); + +  to->type = from->type; +  to->user = g_strdup(from->user); +  to->community = g_strdup(from->community); +} + + +void mwAwareIdBlock_clear(struct mwAwareIdBlock *idb) { +  if(! idb) return; +  g_free(idb->user); +  g_free(idb->community); +  memset(idb, 0x00, sizeof(struct mwAwareIdBlock)); +} + + +guint mwAwareIdBlock_hash(const struct mwAwareIdBlock *a) { +  return (a)? g_str_hash(a->user): 0; +} + + +gboolean mwAwareIdBlock_equal(const struct mwAwareIdBlock *a, +			      const struct mwAwareIdBlock *b) { + +  g_return_val_if_fail(a != NULL, FALSE); +  g_return_val_if_fail(b != NULL, FALSE); +   +  return ( (a->type == b->type) && +	   mw_streq(a->user, b->user) && +	   mw_streq(a->community, b->community) ); +} + + +/* 8.4.2.4 Snapshot */ + +void mwAwareSnapshot_get(struct mwGetBuffer *b, struct mwAwareSnapshot *idb) { + +  /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/presence_fix_v2.diff +  //guint32 junk; +  //char *empty = NULL; +  guint32 end_of_block; +  /// Miranda NG adaptation - end + +  g_return_if_fail(b != NULL); +  g_return_if_fail(idb != NULL); + +  /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/presence_fix_v2.diff +  //guint32_get(b, &junk); +  guint32_get(b, &end_of_block); +  /// Miranda NG adaptation - end +  mwAwareIdBlock_get(b, &idb->id); +  mwString_get(b, &idb->group); +  gboolean_get(b, &idb->online); + +  /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/presence_fix_v2.diff +  //g_free(empty); +  /// Miranda NG adaptation - end + +  if(idb->online) { +    mwString_get(b, &idb->alt_id); +    mwUserStatus_get(b, &idb->status); +    mwString_get(b, &idb->name); +  } + +  /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/presence_fix_v2.diff +  if(b->ptr < b->buf + end_of_block) { +    mwGetBuffer_advance(b, b->buf + end_of_block - b->ptr); +  } +  /// Miranda NG adaptation - end +} + + +void mwAwareSnapshot_clone(struct mwAwareSnapshot *to, +			   const struct mwAwareSnapshot *from) { + +  g_return_if_fail(to != NULL); +  g_return_if_fail(from != NULL); + +  mwAwareIdBlock_clone(&to->id, &from->id); +  if( (to->online = from->online) ) { +    to->alt_id = g_strdup(from->alt_id); +    mwUserStatus_clone(&to->status, &from->status); +    to->name = g_strdup(from->name); +    to->group = g_strdup(from->group); +  } +} + + +void mwAwareSnapshot_clear(struct mwAwareSnapshot *idb) { +  if(! idb) return; +  mwAwareIdBlock_clear(&idb->id); +  mwUserStatus_clear(&idb->status); +  g_free(idb->alt_id); +  g_free(idb->name); +  g_free(idb->group); +  memset(idb, 0x00, sizeof(struct mwAwareSnapshot)); +} + diff --git a/protocols/Sametime/src/meanwhile/src/error.c b/protocols/Sametime/src/meanwhile/src/error.c new file mode 100644 index 0000000000..23c9559802 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/error.c @@ -0,0 +1,97 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <stdio.h> +#include <string.h> + +#include "mw_error.h" + + +static char *err_to_str(guint32 code) { +  static char b[11]; /* 0x12345678 + NULL terminator */ +  sprintf((char *) b, "0x%08x", code); +  b[10] = '\0'; +  return b; +} + + +#define CASE(val, str) \ +case val: \ +  m = str; \ +  break; + + +char* mwError(guint32 code) { +  const char *m; + +  switch(code) { + +    /* 8.3.1.1 General error/success codes */ +    CASE(ERR_SUCCESS, "Success"); +    CASE(ERR_FAILURE, "General failure"); +    CASE(ERR_REQUEST_DELAY, "Request delayed"); +    CASE(ERR_REQUEST_INVALID, "Request is invalid"); +    CASE(ERR_NOT_AUTHORIZED, "Not authorized"); +    CASE(ERR_NO_USER, "User is not online"); +    CASE(ERR_CHANNEL_NO_SUPPORT, "Requested channel is not supported"); +    CASE(ERR_CHANNEL_EXISTS, "Requested channel already exists"); +    CASE(ERR_SERVICE_NO_SUPPORT, "Requested service is not supported"); +    CASE(ERR_PROTOCOL_NO_SUPPORT, "Requested protocol is not supported"); +    CASE(ERR_VERSION_NO_SUPPORT, "Version is not supported"); +    CASE(ERR_USER_SKETCHY, "User is invalid or not trusted"); +    CASE(ERR_ALREADY_INITIALIZED, "Already initialized"); +    CASE(ERR_ENCRYPT_NO_SUPPORT, "Encryption method not supported"); +    CASE(ERR_NO_COMMON_ENCRYPT, "No common encryption method"); +     +    /* 8.3.1.2 Connection/disconnection errors */ +    CASE(VERSION_MISMATCH, "Version mismatch"); +    CASE(FAT_MESSAGE, "Message is too large"); +    CASE(CONNECTION_BROKEN, "Connection broken"); +    CASE(CONNECTION_ABORTED, "Connection aborted"); +    CASE(CONNECTION_REFUSED, "Connection refused"); +    CASE(CONNECTION_RESET, "Connection reset"); +    CASE(CONNECTION_TIMED, "Connection timed out"); +    CASE(CONNECTION_CLOSED, "Connection closed"); +    CASE(INCORRECT_LOGIN, "Incorrect Username/Password"); +    CASE(VERIFICATION_DOWN, "Login verification down or unavailable"); +    CASE(GUEST_IN_USE, "The guest name is currently being used"); +    CASE(MULTI_SERVER_LOGIN, "Login to two different servers concurrently"); +    CASE(MULTI_SERVER_LOGIN2, "Login to two different servers concurrently"); +    CASE(SERVER_BROKEN, "Server misconfiguration"); + +    /* 8.3.1.3 Client error codes */ +    CASE(ERR_CLIENT_USER_GONE, "User is not online"); +    CASE(ERR_CLIENT_USER_DND, "User is in Do Not Disturb mode"); +    CASE(ERR_CLIENT_USER_ELSEWHERE, "Already logged in elsewhere"); + +    /* 8.3.1.4 IM error codes */ +    CASE(ERR_IM_COULDNT_REGISTER, "Cannot register a reserved type"); +    CASE(ERR_IM_ALREADY_REGISTERED, "Requested type is already registered"); +    CASE(ERR_IM_NOT_REGISTERED, "Requested type is not registered"); + +  default: +    m = err_to_str(code); +  } + +  return g_strdup(m); +} + + +#undef CASE diff --git a/protocols/Sametime/src/meanwhile/src/message.c b/protocols/Sametime/src/meanwhile/src/message.c new file mode 100644 index 0000000000..f9afec4c9b --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/message.c @@ -0,0 +1,853 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <glib.h> + +#include "mw_debug.h" +#include "mw_message.h" + + +/* 7.1 Layering and message encapsulation */ +/* 7.1.1 The Sametime Message Header */ + + +static void mwMessageHead_put(struct mwPutBuffer *b, struct mwMessage *msg) { +  guint16_put(b, msg->type); +  guint16_put(b, msg->options); +  guint32_put(b, msg->channel); +   +  if(msg->options & mwMessageOption_HAS_ATTRIBS) +    mwOpaque_put(b, &msg->attribs); +} + + +static void mwMessageHead_get(struct mwGetBuffer *b, struct mwMessage *msg) { + +  if(mwGetBuffer_error(b)) return; + +  guint16_get(b, &msg->type); +  guint16_get(b, &msg->options); +  guint32_get(b, &msg->channel); + +  if(msg->options & mwMessageOption_HAS_ATTRIBS) +    mwOpaque_get(b, &msg->attribs); +} + + +static void mwMessageHead_clone(struct mwMessage *to, +				struct mwMessage *from) { + +  to->type = from->type; +  to->options = from->options; +  to->channel = from->channel; +  mwOpaque_clone(&to->attribs, &from->attribs); +} + + +static void mwMessageHead_clear(struct mwMessage *msg) { +  mwOpaque_clear(&msg->attribs); +} + + +/* 8.4 Messages */ +/* 8.4.1 Basic Community Messages */ +/* 8.4.1.1 Handshake */ + + +static void HANDSHAKE_put(struct mwPutBuffer *b, struct mwMsgHandshake *msg) { +  guint16_put(b, msg->major); +  guint16_put(b, msg->minor); +  guint32_put(b, msg->head.channel); +  guint32_put(b, msg->srvrcalc_addr); +  guint16_put(b, msg->login_type); +  guint32_put(b, msg->loclcalc_addr); +   +  if(msg->major >= 0x001e && msg->minor >= 0x001d) { +    guint16_put(b, msg->unknown_a); +    guint32_put(b, msg->unknown_b); +    mwString_put(b, msg->local_host); +  } +} + + +static void HANDSHAKE_get(struct mwGetBuffer *b, struct mwMsgHandshake *msg) { +  if(mwGetBuffer_error(b)) return; + +  guint16_get(b, &msg->major); +  guint16_get(b, &msg->minor); +  guint32_get(b, &msg->head.channel); +  guint32_get(b, &msg->srvrcalc_addr); +  guint16_get(b, &msg->login_type); +  guint32_get(b, &msg->loclcalc_addr); + +  if(msg->major >= 0x001e && msg->minor >= 0x001d) { +    guint16_get(b, &msg->unknown_a); +    guint32_get(b, &msg->unknown_b); +    mwString_get(b, &msg->local_host); +  } +} + + +static void HANDSHAKE_clear(struct mwMsgHandshake *msg) { +  ; /* nothing to clean up */ +} + + +/* 8.4.1.2 HandshakeAck */ + + +static void HANDSHAKE_ACK_get(struct mwGetBuffer *b, +			      struct mwMsgHandshakeAck *msg) { + +  if(mwGetBuffer_error(b)) return; + +  guint16_get(b, &msg->major); +  guint16_get(b, &msg->minor); +  guint32_get(b, &msg->srvrcalc_addr); + +  /** @todo: get a better handle on what versions support what parts +      of this message. eg: minor version 0x0018 doesn't send the +      following */ +  if(msg->major >= 0x1e && msg->minor > 0x18) { +    guint32_get(b, &msg->magic); +    mwOpaque_get(b, &msg->data); +  } +} + + +static void HANDSHAKE_ACK_put(struct mwPutBuffer *b, +			      struct mwMsgHandshakeAck *msg) { + +  guint16_put(b, msg->major); +  guint16_put(b, msg->minor); +  guint32_put(b, msg->srvrcalc_addr); + +  if(msg->major >= 0x1e && msg->minor > 0x18) { +    guint32_put(b, msg->magic); +    mwOpaque_put(b, &msg->data); +  } +} + + +static void HANDSHAKE_ACK_clear(struct mwMsgHandshakeAck *msg) { +  mwOpaque_clear(&msg->data); +} + + +/* 8.4.1.3 Login */ + + +static void LOGIN_put(struct mwPutBuffer *b, struct mwMsgLogin *msg) { +  guint16_put(b, msg->login_type); +  mwString_put(b, msg->name); + +  /* ordering reversed from houri draft?? */ +  mwOpaque_put(b, &msg->auth_data); +  guint16_put(b, msg->auth_type); + +  guint16_put(b, 0x0000); /* unknown */ +} + + +static void LOGIN_get(struct mwGetBuffer *b, struct mwMsgLogin *msg) { +  if(mwGetBuffer_error(b)) return; + +  guint16_get(b, &msg->login_type); +  mwString_get(b, &msg->name); +  mwOpaque_get(b, &msg->auth_data); +  guint16_get(b, &msg->auth_type); +} + + +static void LOGIN_clear(struct mwMsgLogin *msg) { +  g_free(msg->name);  msg->name = NULL; +  mwOpaque_clear(&msg->auth_data); +} + + +/* 8.4.1.4 LoginAck */ + + +static void LOGIN_ACK_get(struct mwGetBuffer *b, struct mwMsgLoginAck *msg) { +  guint16 junk; + +  if(mwGetBuffer_error(b)) return; + +  mwLoginInfo_get(b, &msg->login); +  guint16_get(b, &junk); +  mwPrivacyInfo_get(b, &msg->privacy); +  mwUserStatus_get(b, &msg->status); +} + + +static void LOGIN_ACK_clear(struct mwMsgLoginAck *msg) { +  mwLoginInfo_clear(&msg->login); +  mwPrivacyInfo_clear(&msg->privacy); +  mwUserStatus_clear(&msg->status); +} + + +/* 8.4.1.5 LoginCont */ + + +static void LOGIN_CONTINUE_put(struct mwPutBuffer *b, +			       struct mwMsgLoginContinue *msg) { + +  ; /* nothing but a message header */ +} + + +static void LOGIN_CONTINUE_get(struct mwGetBuffer *b, +			       struct mwMsgLoginContinue *msg) { + +  ; /* nothing but a message header */ +} + + +static void LOGIN_CONTINUE_clear(struct mwMsgLoginContinue *msg) { +  ; /* this is a very simple message */ +} + + +/* 8.4.1.6 AuthPassed */ + + +static void LOGIN_REDIRECT_get(struct mwGetBuffer *b, +			       struct mwMsgLoginRedirect *msg) { + +  if(mwGetBuffer_error(b)) return; +  mwString_get(b, &msg->host); +  mwString_get(b, &msg->server_id);   +} + + +static void LOGIN_REDIRECT_put(struct mwPutBuffer *b, +			       struct mwMsgLoginRedirect *msg) { +  mwString_put(b, msg->host); +  mwString_put(b, msg->server_id); +} + + +static void LOGIN_REDIRECT_clear(struct mwMsgLoginRedirect *msg) { +  g_free(msg->host); +  msg->host = NULL; + +  g_free(msg->server_id); +  msg->server_id = NULL; +} + + +/* 8.4.1.7 CreateCnl */ + + +static void enc_offer_put(struct mwPutBuffer *b, struct mwEncryptOffer *enc) { +  guint16_put(b, enc->mode); + +  if(enc->items) { +    guint32 count; +    struct mwPutBuffer *p; +    struct mwOpaque o; +    GList *list; + +    /* write the count, items, extra, and flag into a tmp buffer, +       render that buffer into an opaque, and write it into b */ + +    count = g_list_length(enc->items); +    p = mwPutBuffer_new(); + +    guint32_put(p, count); +    for(list = enc->items; list; list = list->next) { +      mwEncryptItem_put(p, list->data); +    } + +    guint16_put(p, enc->extra); +    gboolean_put(p, enc->flag); + +    mwPutBuffer_finalize(&o, p); +    mwOpaque_put(b, &o); +    mwOpaque_clear(&o); +  } +} + + +static void CHANNEL_CREATE_put(struct mwPutBuffer *b, +			       struct mwMsgChannelCreate *msg) { + +  guint32_put(b, msg->reserved); +  guint32_put(b, msg->channel); +  mwIdBlock_put(b, &msg->target); +  guint32_put(b, msg->service); +  guint32_put(b, msg->proto_type); +  guint32_put(b, msg->proto_ver); +  guint32_put(b, msg->options); +  mwOpaque_put(b, &msg->addtl); +  gboolean_put(b, msg->creator_flag); + +  if(msg->creator_flag) +    mwLoginInfo_put(b, &msg->creator); + +  enc_offer_put(b, &msg->encrypt); + +  guint32_put(b, 0x00); +  guint32_put(b, 0x00); +  guint16_put(b, 0x07); +} + + +static void enc_offer_get(struct mwGetBuffer *b, +			  struct mwEncryptOffer *enc) { +  guint32 skip; + +  if(mwGetBuffer_error(b)) return; + +  guint16_get(b, &enc->mode); +  guint32_get(b, &skip); + +  if(skip >= 7) { +    guint32 count; + +    guint32_get(b, &count); + +    while(count-- && (! mwGetBuffer_error(b))) { +      struct mwEncryptItem *ei = g_new0(struct mwEncryptItem, 1); +      mwEncryptItem_get(b, ei); +      enc->items = g_list_append(enc->items, ei); +    } + +    guint16_get(b, &enc->extra); +    gboolean_get(b, &enc->flag); +  } +} + + +static void CHANNEL_CREATE_get(struct mwGetBuffer *b, +			       struct mwMsgChannelCreate *msg) { + +  if(mwGetBuffer_error(b)) return; + +  guint32_get(b, &msg->reserved); +  guint32_get(b, &msg->channel); +  mwIdBlock_get(b, &msg->target); +  guint32_get(b, &msg->service); +  guint32_get(b, &msg->proto_type); +  guint32_get(b, &msg->proto_ver); +  guint32_get(b, &msg->options); +  mwOpaque_get(b, &msg->addtl); +  gboolean_get(b, &msg->creator_flag); +   +  if(msg->creator_flag) +    mwLoginInfo_get(b, &msg->creator); +   +  enc_offer_get(b, &msg->encrypt); +} + + +static void CHANNEL_CREATE_clear(struct mwMsgChannelCreate *msg) { +  GList *list; + +  mwIdBlock_clear(&msg->target); +  mwOpaque_clear(&msg->addtl); +  mwLoginInfo_clear(&msg->creator); +   +  for(list = msg->encrypt.items; list; list = list->next) { +    mwEncryptItem_clear(list->data); +    g_free(list->data); +  } +  g_list_free(msg->encrypt.items); +} + + +/* 8.4.1.8 AcceptCnl */ + + +static void enc_accept_put(struct mwPutBuffer *b, +			   struct mwEncryptAccept *enc) { + +  guint16_put(b, enc->mode); + +  if(enc->item) { +    struct mwPutBuffer *p; +    struct mwOpaque o; + +    p = mwPutBuffer_new(); + +    mwEncryptItem_put(p, enc->item); +    guint16_put(p, enc->extra); +    gboolean_put(p, enc->flag); + +    mwPutBuffer_finalize(&o, p); +    mwOpaque_put(b, &o); +    mwOpaque_clear(&o); +  } +} + + +static void CHANNEL_ACCEPT_put(struct mwPutBuffer *b, +			       struct mwMsgChannelAccept *msg) { +   +  guint32_put(b, msg->service); +  guint32_put(b, msg->proto_type); +  guint32_put(b, msg->proto_ver); +  mwOpaque_put(b, &msg->addtl); +  gboolean_put(b, msg->acceptor_flag); +   +  if(msg->acceptor_flag) +    mwLoginInfo_put(b, &msg->acceptor); +   +  enc_accept_put(b, &msg->encrypt); + +  guint32_put(b, 0x00); +  guint32_put(b, 0x00); +  guint16_put(b, 0x07); +} + + +static void enc_accept_get(struct mwGetBuffer *b, +			   struct mwEncryptAccept *enc) { +  guint32 skip; + +  if(mwGetBuffer_error(b)) return; + +  guint16_get(b, &enc->mode); +  guint32_get(b, &skip); + +  if(skip >= 6) { +    enc->item = g_new0(struct mwEncryptItem, 1); +    mwEncryptItem_get(b, enc->item); +  } + +  if(skip >= 9) { +    guint16_get(b, &enc->extra); +    gboolean_get(b, &enc->flag); +  } +} + + +static void CHANNEL_ACCEPT_get(struct mwGetBuffer *b, +			       struct mwMsgChannelAccept *msg) { + +  if(mwGetBuffer_error(b)) return; + +  guint32_get(b, &msg->service); +  guint32_get(b, &msg->proto_type); +  guint32_get(b, &msg->proto_ver); +  mwOpaque_get(b, &msg->addtl); +  gboolean_get(b, &msg->acceptor_flag); + +  if(msg->acceptor_flag) +    mwLoginInfo_get(b, &msg->acceptor); + +  enc_accept_get(b, &msg->encrypt); +} + + +static void CHANNEL_ACCEPT_clear(struct mwMsgChannelAccept *msg) { +  mwOpaque_clear(&msg->addtl); +  mwLoginInfo_clear(&msg->acceptor); + +  if(msg->encrypt.item) { +    mwEncryptItem_clear(msg->encrypt.item); +    g_free(msg->encrypt.item); +  } +} + + +/* 8.4.1.9 SendOnCnl */ + + +static void CHANNEL_SEND_put(struct mwPutBuffer *b, +			     struct mwMsgChannelSend *msg) { + +  guint16_put(b, msg->type); +  mwOpaque_put(b, &msg->data); +} + + +static void CHANNEL_SEND_get(struct mwGetBuffer *b, +			     struct mwMsgChannelSend *msg) { + +  if(mwGetBuffer_error(b)) return; + +  guint16_get(b, &msg->type); +  mwOpaque_get(b, &msg->data); +} + + +static void CHANNEL_SEND_clear(struct mwMsgChannelSend *msg) { +  mwOpaque_clear(&msg->data); +} + + +/* 8.4.1.10 DestroyCnl */ + + +static void CHANNEL_DESTROY_put(struct mwPutBuffer *b, +				struct mwMsgChannelDestroy *msg) { +  guint32_put(b, msg->reason); +  mwOpaque_put(b, &msg->data); +} + + +static void CHANNEL_DESTROY_get(struct mwGetBuffer *b, +				struct mwMsgChannelDestroy *msg) { + +  if(mwGetBuffer_error(b)) return; + +  guint32_get(b, &msg->reason); +  mwOpaque_get(b, &msg->data); +} + + +static void CHANNEL_DESTROY_clear(struct mwMsgChannelDestroy *msg) { +  mwOpaque_clear(&msg->data); +} + + +/* 8.4.1.11 SetUserStatus */ + + +static void SET_USER_STATUS_put(struct mwPutBuffer *b, +				struct mwMsgSetUserStatus *msg) { +  mwUserStatus_put(b, &msg->status); +} + + +static void SET_USER_STATUS_get(struct mwGetBuffer *b, +				struct mwMsgSetUserStatus *msg) { + +  if(mwGetBuffer_error(b)) return; +  mwUserStatus_get(b, &msg->status); +} + + +static void SET_USER_STATUS_clear(struct mwMsgSetUserStatus *msg) { +  mwUserStatus_clear(&msg->status); +} + + +/* 8.4.1.12 SetPrivacyList */ + + +static void SET_PRIVACY_LIST_put(struct mwPutBuffer *b, +				 struct mwMsgSetPrivacyList *msg) { +  mwPrivacyInfo_put(b, &msg->privacy); +} + + +static void SET_PRIVACY_LIST_get(struct mwGetBuffer *b, +				 struct mwMsgSetPrivacyList *msg) { + +  if(mwGetBuffer_error(b)) return; +  mwPrivacyInfo_get(b, &msg->privacy); +} + + +static void SET_PRIVACY_LIST_clear(struct mwMsgSetPrivacyList *msg) { +  mwPrivacyInfo_clear(&msg->privacy); +} + + +/* Sense Service messages */ + + +static void SENSE_SERVICE_put(struct mwPutBuffer *b, +			      struct mwMsgSenseService *msg) { +  guint32_put(b, msg->service); +} + + +static void SENSE_SERVICE_get(struct mwGetBuffer *b, +			      struct mwMsgSenseService *msg) { + +  if(mwGetBuffer_error(b)) return; +  guint32_get(b, &msg->service); +} + + +static void SENSE_SERVICE_clear(struct mwMsgSenseService *msg) { +  ; +} + + +/* Admin messages */ + + +static void ADMIN_get(struct mwGetBuffer *b, struct mwMsgAdmin *msg) { +  mwString_get(b, &msg->text); +} + + +static void ADMIN_clear(struct mwMsgAdmin *msg) { +  g_free(msg->text); +  msg->text = NULL; +} + + +/* Announcement messages */ + + +static void ANNOUNCE_get(struct mwGetBuffer *b, struct mwMsgAnnounce *msg) { +  struct mwOpaque o = { 0, 0 }; +  struct mwGetBuffer *gb; +  guint32 count; + +  gboolean_get(b, &msg->sender_present); +  if(msg->sender_present) +    mwLoginInfo_get(b, &msg->sender); +  guint16_get(b, &msg->unknown_a); +   +  mwOpaque_get(b, &o); +  gb = mwGetBuffer_wrap(&o); + +  gboolean_get(gb, &msg->may_reply); +  mwString_get(gb, &msg->text); + +  mwGetBuffer_free(gb); +  mwOpaque_clear(&o); + +  guint32_get(b, &count); +  while(count--) { +    char *r = NULL; +    mwString_get(b, &r); +    msg->recipients = g_list_prepend(msg->recipients, r); +  } +} + + +static void ANNOUNCE_put(struct mwPutBuffer *b, struct mwMsgAnnounce *msg) { +  struct mwOpaque o = { 0, 0 }; +  struct mwPutBuffer *pb; +  GList *l; +   +  gboolean_put(b, msg->sender_present); +  if(msg->sender_present) +    mwLoginInfo_put(b, &msg->sender); +  guint16_put(b, msg->unknown_a); + +  pb = mwPutBuffer_new(); +   +  gboolean_put(pb, msg->may_reply); +  mwString_put(pb, msg->text); + +  mwPutBuffer_finalize(&o, pb); +  mwOpaque_put(b, &o); +  mwOpaque_clear(&o); + +  guint32_put(b, g_list_length(msg->recipients)); +  for(l = msg->recipients; l; l = l->next) { +    mwString_put(b, l->data); +  } +} + + +static void ANNOUNCE_clear(struct mwMsgAnnounce *msg) { +  mwLoginInfo_clear(&msg->sender); + +  g_free(msg->text); +  msg->text = NULL; +   +  while(msg->recipients) { +    g_free(msg->recipients->data); +    msg->recipients = g_list_delete_link(msg->recipients, msg->recipients); +  } +} + + +/* general functions */ + + +#define CASE(v, t) \ +case mwMessage_ ## v: \ +  msg = (struct mwMessage *) g_new0(struct t, 1); \ +  msg->type = type; \ +  break; + + +struct mwMessage *mwMessage_new(enum mwMessageType type) { +  struct mwMessage *msg = NULL; +   +  switch(type) { +    CASE(HANDSHAKE, mwMsgHandshake); +    CASE(HANDSHAKE_ACK, mwMsgHandshakeAck); +    CASE(LOGIN, mwMsgLogin); +    CASE(LOGIN_REDIRECT, mwMsgLoginRedirect); +    CASE(LOGIN_CONTINUE, mwMsgLoginContinue); +    CASE(LOGIN_ACK, mwMsgLoginAck); +    CASE(CHANNEL_CREATE, mwMsgChannelCreate); +    CASE(CHANNEL_DESTROY, mwMsgChannelDestroy); +    CASE(CHANNEL_SEND, mwMsgChannelSend); +    CASE(CHANNEL_ACCEPT, mwMsgChannelAccept); +    CASE(SET_USER_STATUS, mwMsgSetUserStatus); +    CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList); +    CASE(SENSE_SERVICE, mwMsgSenseService); +    CASE(ADMIN, mwMsgAdmin); +    CASE(ANNOUNCE, mwMsgAnnounce); +     +  default: +    g_warning("unknown message type 0x%02x\n", type); +  } +   +  return msg; +} + + +#undef CASE + + +/* each type needs to be passed to a specially named _get functions, +   and cast to a specific subclass of mwMessage. */ +#define CASE(v, t) \ +case mwMessage_ ## v: \ +  msg = (struct mwMessage *) g_new0(struct t, 1); \ +  mwMessageHead_clone(msg, &head); \ +  v ## _get(b, (struct t *) msg); \ +  break; + + +struct mwMessage *mwMessage_get(struct mwGetBuffer *b) { +  struct mwMessage *msg = NULL; +  struct mwMessage head; +   +  g_return_val_if_fail(b != NULL, NULL); + +  head.attribs.len = 0; +  head.attribs.data = NULL; + +  /* attempt to read the header first */ +  mwMessageHead_get(b, &head); + +  if(mwGetBuffer_error(b)) { +    mwMessageHead_clear(&head); +    g_warning("problem parsing message head from buffer"); +    return NULL; +  } + +  /* load the rest of the message depending on the header type */ +  switch(head.type) { +    CASE(HANDSHAKE, mwMsgHandshake); +    CASE(HANDSHAKE_ACK, mwMsgHandshakeAck); +    CASE(LOGIN, mwMsgLogin); +    CASE(LOGIN_REDIRECT, mwMsgLoginRedirect); +    CASE(LOGIN_CONTINUE, mwMsgLoginContinue); +    CASE(LOGIN_ACK, mwMsgLoginAck); +    CASE(CHANNEL_CREATE, mwMsgChannelCreate); +    CASE(CHANNEL_DESTROY, mwMsgChannelDestroy); +    CASE(CHANNEL_SEND, mwMsgChannelSend); +    CASE(CHANNEL_ACCEPT, mwMsgChannelAccept); +    CASE(SET_USER_STATUS, mwMsgSetUserStatus); +    CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList); +    CASE(SENSE_SERVICE, mwMsgSenseService); +    CASE(ADMIN, mwMsgAdmin); +    CASE(ANNOUNCE, mwMsgAnnounce); + +  default: +    g_warning("unknown message type 0x%02x, no parse handler", head.type); +  } + +  if(mwGetBuffer_error(b)) { +    g_warning("problem parsing message type 0x%02x, not enough data", +	      head.type); +  } + +  mwMessageHead_clear(&head); +   +  return msg; +} + + +#undef CASE + + +#define CASE(v, t) \ +case mwMessage_ ## v: \ +  v ## _put(b, (struct t *) msg); \ +  break; + + +void mwMessage_put(struct mwPutBuffer *b, struct mwMessage *msg) { + +  g_return_if_fail(b != NULL); +  g_return_if_fail(msg != NULL); + +  mwMessageHead_put(b, msg); + +  switch(msg->type) { +    CASE(HANDSHAKE, mwMsgHandshake); +    CASE(HANDSHAKE_ACK, mwMsgHandshakeAck); +    CASE(LOGIN, mwMsgLogin); +    CASE(LOGIN_REDIRECT, mwMsgLoginRedirect); +    CASE(LOGIN_CONTINUE, mwMsgLoginContinue); +    CASE(CHANNEL_CREATE, mwMsgChannelCreate); +    CASE(CHANNEL_DESTROY, mwMsgChannelDestroy); +    CASE(CHANNEL_SEND, mwMsgChannelSend); +    CASE(CHANNEL_ACCEPT, mwMsgChannelAccept); +    CASE(SET_USER_STATUS, mwMsgSetUserStatus); +    CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList); +    CASE(SENSE_SERVICE, mwMsgSenseService); +    CASE(ANNOUNCE, mwMsgAnnounce); +     +  default: +    ; /* hrm. */ +  } +} + + +#undef CASE + + +#define CASE(v, t) \ +case mwMessage_ ## v: \ +  v ## _clear((struct t *) msg); \ +  break; + + +void mwMessage_free(struct mwMessage *msg) { +  if(! msg) return; + +  mwMessageHead_clear(msg); + +  switch(msg->type) { +    CASE(HANDSHAKE, mwMsgHandshake); +    CASE(HANDSHAKE_ACK, mwMsgHandshakeAck); +    CASE(LOGIN, mwMsgLogin); +    CASE(LOGIN_REDIRECT, mwMsgLoginRedirect); +    CASE(LOGIN_CONTINUE, mwMsgLoginContinue); +    CASE(LOGIN_ACK, mwMsgLoginAck); +    CASE(CHANNEL_CREATE, mwMsgChannelCreate); +    CASE(CHANNEL_DESTROY, mwMsgChannelDestroy); +    CASE(CHANNEL_SEND, mwMsgChannelSend); +    CASE(CHANNEL_ACCEPT, mwMsgChannelAccept); +    CASE(SET_USER_STATUS, mwMsgSetUserStatus); +    CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList); +    CASE(SENSE_SERVICE, mwMsgSenseService); +    CASE(ADMIN, mwMsgAdmin); +    CASE(ANNOUNCE, mwMsgAnnounce); +     +  default: +    ; /* hrm. */ +  } + +  g_free(msg); +} + + +#undef CASE + + diff --git a/protocols/Sametime/src/meanwhile/src/mpi/mpi-config.h b/protocols/Sametime/src/meanwhile/src/mpi/mpi-config.h new file mode 100644 index 0000000000..6972c8878d --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mpi/mpi-config.h @@ -0,0 +1,84 @@ +/* Default configuration for MPI library */ + +#ifndef MPI_CONFIG_H_ +#define MPI_CONFIG_H_ + +/* +  For boolean options,  +  0 = no +  1 = yes + +  Other options are documented individually. + + */ + +#ifndef MP_IOFUNC +#define MP_IOFUNC     0  /* include mp_print() ?                */ +#endif + +#ifndef MP_MODARITH +#define MP_MODARITH   1  /* include modular arithmetic ?        */ +#endif + +#ifndef MP_NUMTH +#define MP_NUMTH      1  /* include number theoretic functions? */ +#endif + +#ifndef MP_LOGTAB +#define MP_LOGTAB     0  /* use table of logs instead of log()? */ +#endif + +#ifndef MP_MEMSET +#define MP_MEMSET     1  /* use memset() to zero buffers?       */ +#endif + +#ifndef MP_MEMCPY +#define MP_MEMCPY     1  /* use memcpy() to copy buffers?       */ +#endif + +#ifndef MP_CRYPTO +#define MP_CRYPTO     0  /* erase memory on free?               */ +#endif + +#ifndef MP_ARGCHK +/* +  0 = no parameter checks +  1 = runtime checks, continue execution and return an error to caller +  2 = assertions; dump core on parameter errors + */ +#define MP_ARGCHK     2  /* how to check input arguments        */ +#endif + +#ifndef MP_DEBUG +#define MP_DEBUG      0  /* print diagnostic output?            */ +#endif + +#ifndef MP_DEFPREC +#define MP_DEFPREC    32 /* default precision, in digits        */ +#endif + +#ifndef MP_MACRO +#define MP_MACRO      1  /* use macros for frequent calls?      */ +#endif + +#ifndef MP_SQUARE +#define MP_SQUARE     1  /* use separate squaring code?         */ +#endif + +#ifndef MP_PTAB_SIZE +/* +  When building mpprime.c, we build in a table of small prime +  values to use for primality testing.  The more you include, +  the more space they take up.  See primes.c for the possible +  values (currently 16, 32, 64, 128, 256, and 6542) + */ +#define MP_PTAB_SIZE  128  /* how many built-in primes?         */ +#endif + +#ifndef MP_COMPAT_MACROS +#define MP_COMPAT_MACROS 0   /* define compatibility macros?    */ +#endif + +#endif /* ifndef MPI_CONFIG_H_ */ + + diff --git a/protocols/Sametime/src/meanwhile/src/mpi/mpi-types.h b/protocols/Sametime/src/meanwhile/src/mpi/mpi-types.h new file mode 100644 index 0000000000..137047ca77 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mpi/mpi-types.h @@ -0,0 +1,18 @@ + +#include <glib.h> + +typedef gchar              mw_mp_sign; +typedef guint16            mw_mp_digit;  /* 2 byte type */ +typedef guint32            mw_mp_word;   /* 4 byte type */ +typedef gsize              mw_mp_size; +typedef gint               mw_mp_err; + +#define MP_DIGIT_BIT       16 +#define MP_DIGIT_MAX       G_MAXUINT16 +#define MP_WORD_BIT        32 +#define MP_WORD_MAX        G_MAXUINT32 + +#define RADIX              (MP_DIGIT_MAX+1) + +#define MP_DIGIT_SIZE      2 +#define DIGIT_FMT          "%04X" diff --git a/protocols/Sametime/src/meanwhile/src/mpi/mpi.c b/protocols/Sametime/src/meanwhile/src/mpi/mpi.c new file mode 100644 index 0000000000..1a33e98525 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mpi/mpi.c @@ -0,0 +1,4022 @@ +/* +  mpi.c +   +  by Michael J. Fromberger <http://www.dartmouth.edu/~sting/> +  Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved +   +  Arbitrary precision integer arithmetic library + +  modified for use in Meanwhile as a convenience library +*/ + +#include "mpi.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#if MP_DEBUG +#include <stdio.h> + +#define DIAG(T,V) {fprintf(stderr,T);mw_mp_print(V,stderr);fputc('\n',stderr);} +#else +#define DIAG(T,V) +#endif + +/*  +   If MP_LOGTAB is not defined, use the math library to compute the +   logarithms on the fly.  Otherwise, use the static table below. +   Pick which works best for your system. + */ +#if MP_LOGTAB + +/* {{{ s_logv_2[] - log table for 2 in various bases */ + +/* +  A table of the logs of 2 for various bases (the 0 and 1 entries of +  this table are meaningless and should not be referenced).   + +  This table is used to compute output lengths for the mw_mp_toradix() +  function.  Since a number n in radix r takes up about log_r(n) +  digits, we estimate the output size by taking the least integer +  greater than log_r(n), where: + +  log_r(n) = log_2(n) * log_r(2) + +  This table, therefore, is a table of log_r(2) for 2 <= r <= 36, +  which are the output bases supported.   + */ + +#include "logtab.h" + +/* }}} */ +#define LOG_V_2(R)  s_logv_2[(R)] + +#else + +#include <math.h> +#define LOG_V_2(R)  (log(2.0)/log(R)) + +#endif + +/* Default precision for newly created mw_mp_int's      */ +static unsigned int s_mw_mp_defprec = MP_DEFPREC; + +/* {{{ Digit arithmetic macros */ + +/* +  When adding and multiplying digits, the results can be larger than +  can be contained in an mw_mp_digit.  Thus, an mw_mp_word is used.  These +  macros mask off the upper and lower digits of the mw_mp_word (the +  mw_mp_word may be more than 2 mw_mp_digits wide, but we only concern +  ourselves with the low-order 2 mw_mp_digits) + +  If your mw_mp_word DOES have more than 2 mw_mp_digits, you need to +  uncomment the first line, and comment out the second. + */ + +/* #define  CARRYOUT(W)  (((W)>>DIGIT_BIT)&MP_DIGIT_MAX) */ +#define  CARRYOUT(W)  ((W)>>DIGIT_BIT) +#define  ACCUM(W)     ((W)&MP_DIGIT_MAX) + +/* }}} */ + +/* {{{ Comparison constants */ + +#define  MP_LT       -1 +#define  MP_EQ        0 +#define  MP_GT        1 + +/* }}} */ + +/* {{{ Constant strings */ + +/* Constant strings returned by mw_mp_strerror() */ +static const char *mw_mp_err_string[] = { +  "unknown result code",     /* say what?            */ +  "boolean true",            /* MP_OKAY, MP_YES      */ +  "boolean false",           /* MP_NO                */ +  "out of memory",           /* MP_MEM               */ +  "argument out of range",   /* MP_RANGE             */ +  "invalid input parameter", /* MP_BADARG            */ +  "result is undefined"      /* MP_UNDEF             */ +}; + +/* Value to digit maps for radix conversion   */ + +/* s_dmap_1 - standard digits and letters */ +static const char *s_dmap_1 =  +  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +#if 0 +/* s_dmap_2 - base64 ordering for digits  */ +static const char *s_dmap_2 = +  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +#endif + +/* }}} */ + +/* {{{ Static function declarations */ + +/*  +   If MP_MACRO is false, these will be defined as actual functions; +   otherwise, suitable macro definitions will be used.  This works +   around the fact that ANSI C89 doesn't support an 'inline' keyword +   (although I hear C9x will ... about bloody time).  At present, the +   macro definitions are identical to the function bodies, but they'll +   expand in place, instead of generating a function call. + +   I chose these particular functions to be made into macros because +   some profiling showed they are called a lot on a typical workload, +   and yet they are primarily housekeeping. + */ +#if MP_MACRO == 0 + void     s_mw_mp_setz(mw_mp_digit *dp, mw_mp_size count); /* zero digits           */ + void     s_mw_mp_copy(mw_mp_digit *sp, mw_mp_digit *dp, mw_mp_size count); /* copy    */ + void    *s_mw_mp_alloc(size_t nb, size_t ni);       /* general allocator     */ + void     s_mw_mp_free(void *ptr);                   /* general free function */ +#else + + /* Even if these are defined as macros, we need to respect the settings +    of the MP_MEMSET and MP_MEMCPY configuration options... +  */ + #if MP_MEMSET == 0 +  #define  s_mw_mp_setz(dp, count) \ +       {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;} + #else +  #define  s_mw_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mw_mp_digit)) + #endif /* MP_MEMSET */ + + #if MP_MEMCPY == 0 +  #define  s_mw_mp_copy(sp, dp, count) \ +       {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];} + #else +  #define  s_mw_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mw_mp_digit)) + #endif /* MP_MEMCPY */ + + #define  s_mw_mp_alloc(nb, ni)  calloc(nb, ni) + #define  s_mw_mp_free(ptr) {if(ptr) free(ptr);} +#endif /* MP_MACRO */ + +mw_mp_err   s_mw_mp_grow(mw_mp_int *mp, mw_mp_size min);   /* increase allocated size */ +mw_mp_err   s_mw_mp_pad(mw_mp_int *mp, mw_mp_size min);    /* left pad with zeroes    */ + +void     s_mw_mp_clamp(mw_mp_int *mp);               /* clip leading zeroes     */ + +void     s_mw_mp_exch(mw_mp_int *a, mw_mp_int *b);      /* swap a and b in place   */ + +mw_mp_err   s_mw_mp_lshd(mw_mp_int *mp, mw_mp_size p);     /* left-shift by p digits  */ +void     s_mw_mp_rshd(mw_mp_int *mp, mw_mp_size p);     /* right-shift by p digits */ +void     s_mw_mp_div_2d(mw_mp_int *mp, mw_mp_digit d);  /* divide by 2^d in place  */ +void     s_mw_mp_mod_2d(mw_mp_int *mp, mw_mp_digit d);  /* modulo 2^d in place     */ +mw_mp_err   s_mw_mp_mul_2d(mw_mp_int *mp, mw_mp_digit d);  /* multiply by 2^d in place*/ +void     s_mw_mp_div_2(mw_mp_int *mp);               /* divide by 2 in place    */ +mw_mp_err   s_mw_mp_mul_2(mw_mp_int *mp);               /* multiply by 2 in place  */ +mw_mp_digit s_mw_mp_norm(mw_mp_int *a, mw_mp_int *b);      /* normalize for division  */ +mw_mp_err   s_mw_mp_add_d(mw_mp_int *mp, mw_mp_digit d);   /* unsigned digit addition */ +mw_mp_err   s_mw_mp_sub_d(mw_mp_int *mp, mw_mp_digit d);   /* unsigned digit subtract */ +mw_mp_err   s_mw_mp_mul_d(mw_mp_int *mp, mw_mp_digit d);   /* unsigned digit multiply */ +mw_mp_err   s_mw_mp_div_d(mw_mp_int *mp, mw_mp_digit d, mw_mp_digit *r); +		                               /* unsigned digit divide   */ +mw_mp_err   s_mw_mp_reduce(mw_mp_int *x, mw_mp_int *m, mw_mp_int *mu); +                                               /* Barrett reduction       */ +mw_mp_err   s_mw_mp_add(mw_mp_int *a, mw_mp_int *b);       /* magnitude addition      */ +mw_mp_err   s_mw_mp_sub(mw_mp_int *a, mw_mp_int *b);       /* magnitude subtract      */ +mw_mp_err   s_mw_mp_mul(mw_mp_int *a, mw_mp_int *b);       /* magnitude multiply      */ +#if 0 +void     s_mw_mp_kmul(mw_mp_digit *a, mw_mp_digit *b, mw_mp_digit *out, mw_mp_size len); +                                               /* multiply buffers in place */ +#endif +#if MP_SQUARE +mw_mp_err   s_mw_mp_sqr(mw_mp_int *a);                  /* magnitude square        */ +#else +#define  s_mw_mp_sqr(a) s_mw_mp_mul(a, a) +#endif +mw_mp_err   s_mw_mp_div(mw_mp_int *a, mw_mp_int *b);       /* magnitude divide        */ +mw_mp_err   s_mw_mp_2expt(mw_mp_int *a, mw_mp_digit k);    /* a = 2^k                 */ +int      s_mw_mp_cmp(mw_mp_int *a, mw_mp_int *b);       /* magnitude comparison    */ +int      s_mw_mp_cmw_mp_d(mw_mp_int *a, mw_mp_digit d);    /* magnitude digit compare */ +int      s_mw_mp_ispow2(mw_mp_int *v);               /* is v a power of 2?      */ +int      s_mw_mp_ispow2d(mw_mp_digit d);             /* is d a power of 2?      */ + +int      s_mw_mp_tovalue(char ch, int r);          /* convert ch to value    */ +char     s_mw_mp_todigit(int val, int r, int low); /* convert val to digit   */ +int      s_mw_mp_outlen(int bits, int r);          /* output length in bytes */ + +/* }}} */ + +/* {{{ Default precision manipulation */ + +unsigned int mw_mp_get_prec(void) +{ +  return s_mw_mp_defprec; + +} /* end mw_mp_get_prec() */ + +void         mw_mp_set_prec(unsigned int prec) +{ +  if(prec == 0) +    s_mw_mp_defprec = MP_DEFPREC; +  else +    s_mw_mp_defprec = prec; + +} /* end mw_mp_set_prec() */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ mw_mp_init(mp) */ + +/* +  mw_mp_init(mp) + +  Initialize a new zero-valued mw_mp_int.  Returns MP_OKAY if successful, +  MP_MEM if memory could not be allocated for the structure. + */ + +mw_mp_err mw_mp_init(mw_mp_int *mp) +{ +  return mw_mp_init_size(mp, s_mw_mp_defprec); + +} /* end mw_mp_init() */ + +/* }}} */ + +/* {{{ mw_mp_init_array(mp[], count) */ + +mw_mp_err mw_mp_init_array(mw_mp_int mp[], int count) +{ +  mw_mp_err  res; +  int     pos; + +  ARGCHK(mp !=NULL && count > 0, MP_BADARG); + +  for(pos = 0; pos < count; ++pos) { +    if((res = mw_mp_init(&mp[pos])) != MP_OKAY) +      goto CLEANUP; +  } + +  return MP_OKAY; + + CLEANUP: +  while(--pos >= 0)  +    mw_mp_clear(&mp[pos]); + +  return res; + +} /* end mw_mp_init_array() */ + +/* }}} */ + +/* {{{ mw_mp_init_size(mp, prec) */ + +/* +  mw_mp_init_size(mp, prec) + +  Initialize a new zero-valued mw_mp_int with at least the given +  precision; returns MP_OKAY if successful, or MP_MEM if memory could +  not be allocated for the structure. + */ + +mw_mp_err mw_mp_init_size(mw_mp_int *mp, mw_mp_size prec) +{ +  ARGCHK(mp != NULL && prec > 0, MP_BADARG); + +  if((DIGITS(mp) = s_mw_mp_alloc(prec, sizeof(mw_mp_digit))) == NULL) +    return MP_MEM; + +  SIGN(mp) = MP_ZPOS; +  USED(mp) = 1; +  ALLOC(mp) = prec; + +  return MP_OKAY; + +} /* end mw_mp_init_size() */ + +/* }}} */ + +/* {{{ mw_mp_init_copy(mp, from) */ + +/* +  mw_mp_init_copy(mp, from) + +  Initialize mp as an exact copy of from.  Returns MP_OKAY if +  successful, MP_MEM if memory could not be allocated for the new +  structure. + */ + +mw_mp_err mw_mp_init_copy(mw_mp_int *mp, mw_mp_int *from) +{ +  ARGCHK(mp != NULL && from != NULL, MP_BADARG); + +  if(mp == from) +    return MP_OKAY; + +  if((DIGITS(mp) = s_mw_mp_alloc(USED(from), sizeof(mw_mp_digit))) == NULL) +    return MP_MEM; + +  s_mw_mp_copy(DIGITS(from), DIGITS(mp), USED(from)); +  USED(mp) = USED(from); +  ALLOC(mp) = USED(from); +  SIGN(mp) = SIGN(from); + +  return MP_OKAY; + +} /* end mw_mp_init_copy() */ + +/* }}} */ + +/* {{{ mw_mp_copy(from, to) */ + +/* +  mw_mp_copy(from, to) + +  Copies the mw_mp_int 'from' to the mw_mp_int 'to'.  It is presumed that +  'to' has already been initialized (if not, use mw_mp_init_copy() +  instead). If 'from' and 'to' are identical, nothing happens. + */ + +mw_mp_err mw_mp_copy(mw_mp_int *from, mw_mp_int *to) +{ +  ARGCHK(from != NULL && to != NULL, MP_BADARG); + +  if(from == to) +    return MP_OKAY; + +  { /* copy */ +    mw_mp_digit   *tmp; + +    /* +      If the allocated buffer in 'to' already has enough space to hold +      all the used digits of 'from', we'll re-use it to avoid hitting +      the memory allocater more than necessary; otherwise, we'd have +      to grow anyway, so we just allocate a hunk and make the copy as +      usual +     */ +    if(ALLOC(to) >= USED(from)) { +      s_mw_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from)); +      s_mw_mp_copy(DIGITS(from), DIGITS(to), USED(from)); +       +    } else { +      if((tmp = s_mw_mp_alloc(USED(from), sizeof(mw_mp_digit))) == NULL) +	return MP_MEM; + +      s_mw_mp_copy(DIGITS(from), tmp, USED(from)); + +      if(DIGITS(to) != NULL) { +#if MP_CRYPTO +	s_mw_mp_setz(DIGITS(to), ALLOC(to)); +#endif +	s_mw_mp_free(DIGITS(to)); +      } + +      DIGITS(to) = tmp; +      ALLOC(to) = USED(from); +    } + +    /* Copy the precision and sign from the original */ +    USED(to) = USED(from); +    SIGN(to) = SIGN(from); +  } /* end copy */ + +  return MP_OKAY; + +} /* end mw_mp_copy() */ + +/* }}} */ + +/* {{{ mw_mp_exch(mp1, mp2) */ + +/* +  mw_mp_exch(mp1, mp2) + +  Exchange mp1 and mp2 without allocating any intermediate memory +  (well, unless you count the stack space needed for this call and the +  locals it creates...).  This cannot fail. + */ + +void mw_mp_exch(mw_mp_int *mp1, mw_mp_int *mp2) +{ +#if MP_ARGCHK == 2 +  assert(mp1 != NULL && mp2 != NULL); +#else +  if(mp1 == NULL || mp2 == NULL) +    return; +#endif + +  s_mw_mp_exch(mp1, mp2); + +} /* end mw_mp_exch() */ + +/* }}} */ + +/* {{{ mw_mp_clear(mp) */ + +/* +  mw_mp_clear(mp) + +  Release the storage used by an mw_mp_int, and void its fields so that +  if someone calls mw_mp_clear() again for the same int later, we won't +  get tollchocked. + */ + +void   mw_mp_clear(mw_mp_int *mp) +{ +  if(mp == NULL) +    return; + +  if(DIGITS(mp) != NULL) { +#if MP_CRYPTO +    s_mw_mp_setz(DIGITS(mp), ALLOC(mp)); +#endif +    s_mw_mp_free(DIGITS(mp)); +    DIGITS(mp) = NULL; +  } + +  USED(mp) = 0; +  ALLOC(mp) = 0; + +} /* end mw_mp_clear() */ + +/* }}} */ + +/* {{{ mw_mp_clear_array(mp[], count) */ + +void   mw_mp_clear_array(mw_mp_int mp[], int count) +{ +  ARGCHK(mp != NULL && count > 0, MP_BADARG); + +  while(--count >= 0)  +    mw_mp_clear(&mp[count]); + +} /* end mw_mp_clear_array() */ + +/* }}} */ + +/* {{{ mw_mp_zero(mp) */ + +/* +  mw_mp_zero(mp)  + +  Set mp to zero.  Does not change the allocated size of the structure, +  and therefore cannot fail (except on a bad argument, which we ignore) + */ +void   mw_mp_zero(mw_mp_int *mp) +{ +  if(mp == NULL) +    return; + +  s_mw_mp_setz(DIGITS(mp), ALLOC(mp)); +  USED(mp) = 1; +  SIGN(mp) = MP_ZPOS; + +} /* end mw_mp_zero() */ + +/* }}} */ + +/* {{{ mw_mp_set(mp, d) */ + +void   mw_mp_set(mw_mp_int *mp, mw_mp_digit d) +{ +  if(mp == NULL) +    return; + +  mw_mp_zero(mp); +  DIGIT(mp, 0) = d; + +} /* end mw_mp_set() */ + +/* }}} */ + +/* {{{ mw_mp_set_int(mp, z) */ + +mw_mp_err mw_mp_set_int(mw_mp_int *mp, long z) +{ +  int            ix; +  unsigned long  v = abs(z); +  mw_mp_err         res; + +  ARGCHK(mp != NULL, MP_BADARG); + +  mw_mp_zero(mp); +  if(z == 0) +    return MP_OKAY;  /* shortcut for zero */ + +  for(ix = sizeof(long) - 1; ix >= 0; ix--) { + +    if((res = s_mw_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) +      return res; + +    res = s_mw_mp_add_d(mp,  +		     (mw_mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX)); +    if(res != MP_OKAY) +      return res; + +  } + +  if(z < 0) +    SIGN(mp) = MP_NEG; + +  return MP_OKAY; + +} /* end mw_mp_set_int() */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Digit arithmetic */ + +/* {{{ mw_mp_add_d(a, d, b) */ + +/* +  mw_mp_add_d(a, d, b) + +  Compute the sum b = a + d, for a single digit d.  Respects the sign of +  its primary addend (single digits are unsigned anyway). + */ + +mw_mp_err mw_mp_add_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b) +{ +  mw_mp_err   res = MP_OKAY; + +  ARGCHK(a != NULL && b != NULL, MP_BADARG); + +  if((res = mw_mp_copy(a, b)) != MP_OKAY) +    return res; + +  if(SIGN(b) == MP_ZPOS) { +    res = s_mw_mp_add_d(b, d); +  } else if(s_mw_mp_cmw_mp_d(b, d) >= 0) { +    res = s_mw_mp_sub_d(b, d); +  } else { +    SIGN(b) = MP_ZPOS; + +    DIGIT(b, 0) = d - DIGIT(b, 0); +  } + +  return res; + +} /* end mw_mp_add_d() */ + +/* }}} */ + +/* {{{ mw_mp_sub_d(a, d, b) */ + +/* +  mw_mp_sub_d(a, d, b) + +  Compute the difference b = a - d, for a single digit d.  Respects the +  sign of its subtrahend (single digits are unsigned anyway). + */ + +mw_mp_err mw_mp_sub_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b) +{ +  mw_mp_err   res; + +  ARGCHK(a != NULL && b != NULL, MP_BADARG); + +  if((res = mw_mp_copy(a, b)) != MP_OKAY) +    return res; + +  if(SIGN(b) == MP_NEG) { +    if((res = s_mw_mp_add_d(b, d)) != MP_OKAY) +      return res; + +  } else if(s_mw_mp_cmw_mp_d(b, d) >= 0) { +    if((res = s_mw_mp_sub_d(b, d)) != MP_OKAY) +      return res; + +  } else { +    mw_mp_neg(b, b); + +    DIGIT(b, 0) = d - DIGIT(b, 0); +    SIGN(b) = MP_NEG; +  } + +  if(s_mw_mp_cmw_mp_d(b, 0) == 0) +    SIGN(b) = MP_ZPOS; + +  return MP_OKAY; + +} /* end mw_mp_sub_d() */ + +/* }}} */ + +/* {{{ mw_mp_mul_d(a, d, b) */ + +/* +  mw_mp_mul_d(a, d, b) + +  Compute the product b = a * d, for a single digit d.  Respects the sign +  of its multiplicand (single digits are unsigned anyway) + */ + +mw_mp_err mw_mp_mul_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b) +{ +  mw_mp_err  res; + +  ARGCHK(a != NULL && b != NULL, MP_BADARG); + +  if(d == 0) { +    mw_mp_zero(b); +    return MP_OKAY; +  } + +  if((res = mw_mp_copy(a, b)) != MP_OKAY) +    return res; + +  res = s_mw_mp_mul_d(b, d); + +  return res; + +} /* end mw_mp_mul_d() */ + +/* }}} */ + +/* {{{ mw_mp_mul_2(a, c) */ + +mw_mp_err mw_mp_mul_2(mw_mp_int *a, mw_mp_int *c) +{ +  mw_mp_err  res; + +  ARGCHK(a != NULL && c != NULL, MP_BADARG); + +  if((res = mw_mp_copy(a, c)) != MP_OKAY) +    return res; + +  return s_mw_mp_mul_2(c); + +} /* end mw_mp_mul_2() */ + +/* }}} */ + +/* {{{ mw_mp_div_d(a, d, q, r) */ + +/* +  mw_mp_div_d(a, d, q, r) + +  Compute the quotient q = a / d and remainder r = a mod d, for a +  single digit d.  Respects the sign of its divisor (single digits are +  unsigned anyway). + */ + +mw_mp_err mw_mp_div_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *q, mw_mp_digit *r) +{ +  mw_mp_err   res; +  mw_mp_digit rem; +  int      pow; + +  ARGCHK(a != NULL, MP_BADARG); + +  if(d == 0) +    return MP_RANGE; + +  /* Shortcut for powers of two ... */ +  if((pow = s_mw_mp_ispow2d(d)) >= 0) { +    mw_mp_digit  mask; + +    mask = (1 << pow) - 1; +    rem = DIGIT(a, 0) & mask; + +    if(q) { +      mw_mp_copy(a, q); +      s_mw_mp_div_2d(q, pow); +    } + +    if(r) +      *r = rem; + +    return MP_OKAY; +  } + +  /* +    If the quotient is actually going to be returned, we'll try to +    avoid hitting the memory allocator by copying the dividend into it +    and doing the division there.  This can't be any _worse_ than +    always copying, and will sometimes be better (since it won't make +    another copy) + +    If it's not going to be returned, we need to allocate a temporary +    to hold the quotient, which will just be discarded. +   */ +  if(q) { +    if((res = mw_mp_copy(a, q)) != MP_OKAY) +      return res; + +    res = s_mw_mp_div_d(q, d, &rem); +    if(s_mw_mp_cmw_mp_d(q, 0) == MP_EQ) +      SIGN(q) = MP_ZPOS; + +  } else { +    mw_mp_int  qp; + +    if((res = mw_mp_init_copy(&qp, a)) != MP_OKAY) +      return res; + +    res = s_mw_mp_div_d(&qp, d, &rem); +    if(s_mw_mp_cmw_mp_d(&qp, 0) == 0) +      SIGN(&qp) = MP_ZPOS; + +    mw_mp_clear(&qp); +  } + +  if(r) +    *r = rem; + +  return res; + +} /* end mw_mp_div_d() */ + +/* }}} */ + +/* {{{ mw_mp_div_2(a, c) */ + +/* +  mw_mp_div_2(a, c) + +  Compute c = a / 2, disregarding the remainder. + */ + +mw_mp_err mw_mp_div_2(mw_mp_int *a, mw_mp_int *c) +{ +  mw_mp_err  res; + +  ARGCHK(a != NULL && c != NULL, MP_BADARG); + +  if((res = mw_mp_copy(a, c)) != MP_OKAY) +    return res; + +  s_mw_mp_div_2(c); + +  return MP_OKAY; + +} /* end mw_mp_div_2() */ + +/* }}} */ + +/* {{{ mw_mp_expt_d(a, d, b) */ + +mw_mp_err mw_mp_expt_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *c) +{ +  mw_mp_int   s, x; +  mw_mp_err   res; +  mw_mp_sign  cs = MP_ZPOS; + +  ARGCHK(a != NULL && c != NULL, MP_BADARG); + +  if((res = mw_mp_init(&s)) != MP_OKAY) +    return res; +  if((res = mw_mp_init_copy(&x, a)) != MP_OKAY) +    goto X; + +  DIGIT(&s, 0) = 1; + +  if((d % 2) == 1) +    cs = SIGN(a); + +  while(d != 0) { +    if(d & 1) { +      if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY) +	goto CLEANUP; +    } + +    d >>= 1; + +    if((res = s_mw_mp_sqr(&x)) != MP_OKAY) +      goto CLEANUP; +  } + +  SIGN(&s) = cs; + +  s_mw_mp_exch(&s, c); + +CLEANUP: +  mw_mp_clear(&x); +X: +  mw_mp_clear(&s); + +  return res; + +} /* end mw_mp_expt_d() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Full arithmetic */ + +/* {{{ mw_mp_abs(a, b) */ + +/* +  mw_mp_abs(a, b) + +  Compute b = |a|.  'a' and 'b' may be identical. + */ + +mw_mp_err mw_mp_abs(mw_mp_int *a, mw_mp_int *b) +{ +  mw_mp_err   res; + +  ARGCHK(a != NULL && b != NULL, MP_BADARG); + +  if((res = mw_mp_copy(a, b)) != MP_OKAY) +    return res; + +  SIGN(b) = MP_ZPOS; + +  return MP_OKAY; + +} /* end mw_mp_abs() */ + +/* }}} */ + +/* {{{ mw_mp_neg(a, b) */ + +/* +  mw_mp_neg(a, b) + +  Compute b = -a.  'a' and 'b' may be identical. + */ + +mw_mp_err mw_mp_neg(mw_mp_int *a, mw_mp_int *b) +{ +  mw_mp_err   res; + +  ARGCHK(a != NULL && b != NULL, MP_BADARG); + +  if((res = mw_mp_copy(a, b)) != MP_OKAY) +    return res; + +  if(s_mw_mp_cmw_mp_d(b, 0) == MP_EQ)  +    SIGN(b) = MP_ZPOS; +  else  +    SIGN(b) = (SIGN(b) == MP_NEG) ? MP_ZPOS : MP_NEG; + +  return MP_OKAY; + +} /* end mw_mp_neg() */ + +/* }}} */ + +/* {{{ mw_mp_add(a, b, c) */ + +/* +  mw_mp_add(a, b, c) + +  Compute c = a + b.  All parameters may be identical. + */ + +mw_mp_err mw_mp_add(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c) +{ +  mw_mp_err  res; +  int     cmp; + +  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + +  if(SIGN(a) == SIGN(b)) { /* same sign:  add values, keep sign */ + +    /* Commutativity of addition lets us do this in either order, +       so we avoid having to use a temporary even if the result  +       is supposed to replace the output +     */ +    if(c == b) { +      if((res = s_mw_mp_add(c, a)) != MP_OKAY) +	return res; +    } else { +      if(c != a && (res = mw_mp_copy(a, c)) != MP_OKAY) +	return res; + +      if((res = s_mw_mp_add(c, b)) != MP_OKAY)  +	return res; +    } + +  } else if((cmp = s_mw_mp_cmp(a, b)) > 0) {  /* different sign: a > b   */ + +    /* If the output is going to be clobbered, we will use a temporary +       variable; otherwise, we'll do it without touching the memory  +       allocator at all, if possible +     */ +    if(c == b) { +      mw_mp_int  tmp; + +      if((res = mw_mp_init_copy(&tmp, a)) != MP_OKAY) +	return res; +      if((res = s_mw_mp_sub(&tmp, b)) != MP_OKAY) { +	mw_mp_clear(&tmp); +	return res; +      } + +      s_mw_mp_exch(&tmp, c); +      mw_mp_clear(&tmp); + +    } else { + +      if(c != a && (res = mw_mp_copy(a, c)) != MP_OKAY) +	return res; +      if((res = s_mw_mp_sub(c, b)) != MP_OKAY) +	return res; + +    } + +  } else if(cmp == 0) {             /* different sign, a == b   */ + +    mw_mp_zero(c); +    return MP_OKAY; + +  } else {                          /* different sign: a < b    */ + +    /* See above... */ +    if(c == a) { +      mw_mp_int  tmp; + +      if((res = mw_mp_init_copy(&tmp, b)) != MP_OKAY) +	return res; +      if((res = s_mw_mp_sub(&tmp, a)) != MP_OKAY) { +	mw_mp_clear(&tmp); +	return res; +      } + +      s_mw_mp_exch(&tmp, c); +      mw_mp_clear(&tmp); + +    } else { + +      if(c != b && (res = mw_mp_copy(b, c)) != MP_OKAY) +	return res; +      if((res = s_mw_mp_sub(c, a)) != MP_OKAY) +	return res; + +    } +  } + +  if(USED(c) == 1 && DIGIT(c, 0) == 0) +    SIGN(c) = MP_ZPOS; + +  return MP_OKAY; + +} /* end mw_mp_add() */ + +/* }}} */ + +/* {{{ mw_mp_sub(a, b, c) */ + +/* +  mw_mp_sub(a, b, c) + +  Compute c = a - b.  All parameters may be identical. + */ + +mw_mp_err mw_mp_sub(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c) +{ +  mw_mp_err  res; +  int     cmp; + +  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + +  if(SIGN(a) != SIGN(b)) { +    if(c == a) { +      if((res = s_mw_mp_add(c, b)) != MP_OKAY) +	return res; +    } else { +      if(c != b && ((res = mw_mp_copy(b, c)) != MP_OKAY)) +	return res; +      if((res = s_mw_mp_add(c, a)) != MP_OKAY) +	return res; +      SIGN(c) = SIGN(a); +    } + +  } else if((cmp = s_mw_mp_cmp(a, b)) > 0) { /* Same sign, a > b */ +    if(c == b) { +      mw_mp_int  tmp; + +      if((res = mw_mp_init_copy(&tmp, a)) != MP_OKAY) +	return res; +      if((res = s_mw_mp_sub(&tmp, b)) != MP_OKAY) { +	mw_mp_clear(&tmp); +	return res; +      } +      s_mw_mp_exch(&tmp, c); +      mw_mp_clear(&tmp); + +    } else { +      if(c != a && ((res = mw_mp_copy(a, c)) != MP_OKAY)) +	return res; + +      if((res = s_mw_mp_sub(c, b)) != MP_OKAY) +	return res; +    } + +  } else if(cmp == 0) {  /* Same sign, equal magnitude */ +    mw_mp_zero(c); +    return MP_OKAY; + +  } else {               /* Same sign, b > a */ +    if(c == a) { +      mw_mp_int  tmp; + +      if((res = mw_mp_init_copy(&tmp, b)) != MP_OKAY) +	return res; + +      if((res = s_mw_mp_sub(&tmp, a)) != MP_OKAY) { +	mw_mp_clear(&tmp); +	return res; +      } +      s_mw_mp_exch(&tmp, c); +      mw_mp_clear(&tmp); + +    } else { +      if(c != b && ((res = mw_mp_copy(b, c)) != MP_OKAY))  +	return res; + +      if((res = s_mw_mp_sub(c, a)) != MP_OKAY) +	return res; +    } + +    SIGN(c) = !SIGN(b); +  } + +  if(USED(c) == 1 && DIGIT(c, 0) == 0) +    SIGN(c) = MP_ZPOS; + +  return MP_OKAY; + +} /* end mw_mp_sub() */ + +/* }}} */ + +/* {{{ mw_mp_mul(a, b, c) */ + +/* +  mw_mp_mul(a, b, c) + +  Compute c = a * b.  All parameters may be identical. + */ + +mw_mp_err mw_mp_mul(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c) +{ +  mw_mp_err   res; +  mw_mp_sign  sgn; + +  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + +  sgn = (SIGN(a) == SIGN(b)) ? MP_ZPOS : MP_NEG; + +  if(c == b) { +    if((res = s_mw_mp_mul(c, a)) != MP_OKAY) +      return res; + +  } else { +    if((res = mw_mp_copy(a, c)) != MP_OKAY) +      return res; + +    if((res = s_mw_mp_mul(c, b)) != MP_OKAY) +      return res; +  } +   +  if(sgn == MP_ZPOS || s_mw_mp_cmw_mp_d(c, 0) == MP_EQ) +    SIGN(c) = MP_ZPOS; +  else +    SIGN(c) = sgn; +   +  return MP_OKAY; + +} /* end mw_mp_mul() */ + +/* }}} */ + +/* {{{ mw_mp_mul_2d(a, d, c) */ + +/* +  mw_mp_mul_2d(a, d, c) + +  Compute c = a * 2^d.  a may be the same as c. + */ + +mw_mp_err mw_mp_mul_2d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *c) +{ +  mw_mp_err   res; + +  ARGCHK(a != NULL && c != NULL, MP_BADARG); + +  if((res = mw_mp_copy(a, c)) != MP_OKAY) +    return res; + +  if(d == 0) +    return MP_OKAY; + +  return s_mw_mp_mul_2d(c, d); + +} /* end mw_mp_mul() */ + +/* }}} */ + +/* {{{ mw_mp_sqr(a, b) */ + +#if MP_SQUARE +mw_mp_err mw_mp_sqr(mw_mp_int *a, mw_mp_int *b) +{ +  mw_mp_err   res; + +  ARGCHK(a != NULL && b != NULL, MP_BADARG); + +  if((res = mw_mp_copy(a, b)) != MP_OKAY) +    return res; + +  if((res = s_mw_mp_sqr(b)) != MP_OKAY) +    return res; + +  SIGN(b) = MP_ZPOS; + +  return MP_OKAY; + +} /* end mw_mp_sqr() */ +#endif + +/* }}} */ + +/* {{{ mw_mp_div(a, b, q, r) */ + +/* +  mw_mp_div(a, b, q, r) + +  Compute q = a / b and r = a mod b.  Input parameters may be re-used +  as output parameters.  If q or r is NULL, that portion of the +  computation will be discarded (although it will still be computed) + +  Pay no attention to the hacker behind the curtain. + */ + +mw_mp_err mw_mp_div(mw_mp_int *a, mw_mp_int *b, mw_mp_int *q, mw_mp_int *r) +{ +  mw_mp_err   res; +  mw_mp_int   qtmp, rtmp; +  int      cmp; + +  ARGCHK(a != NULL && b != NULL, MP_BADARG); + +  if(mw_mp_cmw_mp_z(b) == MP_EQ) +    return MP_RANGE; + +  /* If a <= b, we can compute the solution without division, and +     avoid any memory allocation +   */ +  if((cmp = s_mw_mp_cmp(a, b)) < 0) { +    if(r) { +      if((res = mw_mp_copy(a, r)) != MP_OKAY) +	return res; +    } + +    if(q)  +      mw_mp_zero(q); + +    return MP_OKAY; + +  } else if(cmp == 0) { + +    /* Set quotient to 1, with appropriate sign */ +    if(q) { +      int qneg = (SIGN(a) != SIGN(b)); + +      mw_mp_set(q, 1); +      if(qneg) +	SIGN(q) = MP_NEG; +    } + +    if(r) +      mw_mp_zero(r); + +    return MP_OKAY; +  } + +  /* If we get here, it means we actually have to do some division */ + +  /* Set up some temporaries... */ +  if((res = mw_mp_init_copy(&qtmp, a)) != MP_OKAY) +    return res; +  if((res = mw_mp_init_copy(&rtmp, b)) != MP_OKAY) +    goto CLEANUP; + +  if((res = s_mw_mp_div(&qtmp, &rtmp)) != MP_OKAY) +    goto CLEANUP; + +  /* Compute the signs for the output  */ +  SIGN(&rtmp) = SIGN(a); /* Sr = Sa              */ +  if(SIGN(a) == SIGN(b)) +    SIGN(&qtmp) = MP_ZPOS;  /* Sq = MP_ZPOS if Sa = Sb */ +  else +    SIGN(&qtmp) = MP_NEG;   /* Sq = MP_NEG if Sa != Sb */ + +  if(s_mw_mp_cmw_mp_d(&qtmp, 0) == MP_EQ) +    SIGN(&qtmp) = MP_ZPOS; +  if(s_mw_mp_cmw_mp_d(&rtmp, 0) == MP_EQ) +    SIGN(&rtmp) = MP_ZPOS; + +  /* Copy output, if it is needed      */ +  if(q)  +    s_mw_mp_exch(&qtmp, q); + +  if(r)  +    s_mw_mp_exch(&rtmp, r); + +CLEANUP: +  mw_mp_clear(&rtmp); +  mw_mp_clear(&qtmp); + +  return res; + +} /* end mw_mp_div() */ + +/* }}} */ + +/* {{{ mw_mp_div_2d(a, d, q, r) */ + +mw_mp_err mw_mp_div_2d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *q, mw_mp_int *r) +{ +  mw_mp_err  res; + +  ARGCHK(a != NULL, MP_BADARG); + +  if(q) { +    if((res = mw_mp_copy(a, q)) != MP_OKAY) +      return res; + +    s_mw_mp_div_2d(q, d); +  } + +  if(r) { +    if((res = mw_mp_copy(a, r)) != MP_OKAY) +      return res; + +    s_mw_mp_mod_2d(r, d); +  } + +  return MP_OKAY; + +} /* end mw_mp_div_2d() */ + +/* }}} */ + +/* {{{ mw_mp_expt(a, b, c) */ + +/* +  mw_mp_expt(a, b, c) + +  Compute c = a ** b, that is, raise a to the b power.  Uses a +  standard iterative square-and-multiply technique. + */ + +mw_mp_err mw_mp_expt(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c) +{ +  mw_mp_int   s, x; +  mw_mp_err   res; +  mw_mp_digit d; + +  /// Miranda NG adaptation start - MSVC +  ///int      dig, bit; +  int bit; +  mw_mp_size dig; +  /// Miranda NG adaptation end + +  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + +  if(mw_mp_cmw_mp_z(b) < 0) +    return MP_RANGE; + +  if((res = mw_mp_init(&s)) != MP_OKAY) +    return res; + +  mw_mp_set(&s, 1); + +  if((res = mw_mp_init_copy(&x, a)) != MP_OKAY) +    goto X; + +  /* Loop over low-order digits in ascending order */ +  for(dig = 0; dig < (USED(b) - 1); dig++) { +    d = DIGIT(b, dig); + +    /* Loop over bits of each non-maximal digit */ +    for(bit = 0; bit < DIGIT_BIT; bit++) { +      if(d & 1) { +	if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY)  +	  goto CLEANUP; +      } + +      d >>= 1; +       +      if((res = s_mw_mp_sqr(&x)) != MP_OKAY) +	goto CLEANUP; +    } +  } + +  /* Consider now the last digit... */ +  d = DIGIT(b, dig); + +  while(d) { +    if(d & 1) { +      if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY) +	goto CLEANUP; +    } + +    d >>= 1; + +    if((res = s_mw_mp_sqr(&x)) != MP_OKAY) +      goto CLEANUP; +  } +   +  if(mw_mp_iseven(b)) +    SIGN(&s) = SIGN(a); + +  res = mw_mp_copy(&s, c); + +CLEANUP: +  mw_mp_clear(&x); +X: +  mw_mp_clear(&s); + +  return res; + +} /* end mw_mp_expt() */ + +/* }}} */ + +/* {{{ mw_mp_2expt(a, k) */ + +/* Compute a = 2^k */ + +mw_mp_err mw_mp_2expt(mw_mp_int *a, mw_mp_digit k) +{ +  ARGCHK(a != NULL, MP_BADARG); + +  return s_mw_mp_2expt(a, k); + +} /* end mw_mp_2expt() */ + +/* }}} */ + +/* {{{ mw_mp_mod(a, m, c) */ + +/* +  mw_mp_mod(a, m, c) + +  Compute c = a (mod m).  Result will always be 0 <= c < m. + */ + +mw_mp_err mw_mp_mod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c) +{ +  mw_mp_err  res; +  int     mag; + +  ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); + +  if(SIGN(m) == MP_NEG) +    return MP_RANGE; + +  /* +     If |a| > m, we need to divide to get the remainder and take the +     absolute value.   + +     If |a| < m, we don't need to do any division, just copy and adjust +     the sign (if a is negative). + +     If |a| == m, we can simply set the result to zero. + +     This order is intended to minimize the average path length of the +     comparison chain on common workloads -- the most frequent cases are +     that |a| != m, so we do those first. +   */ +  if((mag = s_mw_mp_cmp(a, m)) > 0) { +    if((res = mw_mp_div(a, m, NULL, c)) != MP_OKAY) +      return res; +     +    if(SIGN(c) == MP_NEG) { +      if((res = mw_mp_add(c, m, c)) != MP_OKAY) +	return res; +    } + +  } else if(mag < 0) { +    if((res = mw_mp_copy(a, c)) != MP_OKAY) +      return res; + +    if(mw_mp_cmw_mp_z(a) < 0) { +      if((res = mw_mp_add(c, m, c)) != MP_OKAY) +	return res; + +    } +     +  } else { +    mw_mp_zero(c); + +  } + +  return MP_OKAY; + +} /* end mw_mp_mod() */ + +/* }}} */ + +/* {{{ mw_mp_mod_d(a, d, c) */ + +/* +  mw_mp_mod_d(a, d, c) + +  Compute c = a (mod d).  Result will always be 0 <= c < d + */ +mw_mp_err mw_mp_mod_d(mw_mp_int *a, mw_mp_digit d, mw_mp_digit *c) +{ +  mw_mp_err   res; +  mw_mp_digit rem; + +  ARGCHK(a != NULL && c != NULL, MP_BADARG); + +  if(s_mw_mp_cmw_mp_d(a, d) > 0) { +    if((res = mw_mp_div_d(a, d, NULL, &rem)) != MP_OKAY) +      return res; + +  } else { +    if(SIGN(a) == MP_NEG) +      rem = d - DIGIT(a, 0); +    else +      rem = DIGIT(a, 0); +  } + +  if(c) +    *c = rem; + +  return MP_OKAY; + +} /* end mw_mp_mod_d() */ + +/* }}} */ + +/* {{{ mw_mp_sqrt(a, b) */ + +/* +  mw_mp_sqrt(a, b) + +  Compute the integer square root of a, and store the result in b. +  Uses an integer-arithmetic version of Newton's iterative linear +  approximation technique to determine this value; the result has the +  following two properties: + +     b^2 <= a +     (b+1)^2 >= a + +  It is a range error to pass a negative value. + */ +mw_mp_err mw_mp_sqrt(mw_mp_int *a, mw_mp_int *b) +{ +  mw_mp_int   x, t; +  mw_mp_err   res; + +  ARGCHK(a != NULL && b != NULL, MP_BADARG); + +  /* Cannot take square root of a negative value */ +  if(SIGN(a) == MP_NEG) +    return MP_RANGE; + +  /* Special cases for zero and one, trivial     */ +  if(mw_mp_cmw_mp_d(a, 0) == MP_EQ || mw_mp_cmw_mp_d(a, 1) == MP_EQ)  +    return mw_mp_copy(a, b); +     +  /* Initialize the temporaries we'll use below  */ +  if((res = mw_mp_init_size(&t, USED(a))) != MP_OKAY) +    return res; + +  /* Compute an initial guess for the iteration as a itself */ +  if((res = mw_mp_init_copy(&x, a)) != MP_OKAY) +    goto X; + +  for(;;) { +    /* t = (x * x) - a */ +    mw_mp_copy(&x, &t);      /* can't fail, t is big enough for original x */ +    if((res = mw_mp_sqr(&t, &t)) != MP_OKAY || +       (res = mw_mp_sub(&t, a, &t)) != MP_OKAY) +      goto CLEANUP; + +    /* t = t / 2x       */ +    s_mw_mp_mul_2(&x); +    if((res = mw_mp_div(&t, &x, &t, NULL)) != MP_OKAY) +      goto CLEANUP; +    s_mw_mp_div_2(&x); + +    /* Terminate the loop, if the quotient is zero */ +    if(mw_mp_cmw_mp_z(&t) == MP_EQ) +      break; + +    /* x = x - t       */ +    if((res = mw_mp_sub(&x, &t, &x)) != MP_OKAY) +      goto CLEANUP; + +  } + +  /* Copy result to output parameter */ +  mw_mp_sub_d(&x, 1, &x); +  s_mw_mp_exch(&x, b); + + CLEANUP: +  mw_mp_clear(&x); + X: +  mw_mp_clear(&t);  + +  return res; + +} /* end mw_mp_sqrt() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Modular arithmetic */ + +#if MP_MODARITH +/* {{{ mw_mp_addmod(a, b, m, c) */ + +/* +  mw_mp_addmod(a, b, m, c) + +  Compute c = (a + b) mod m + */ + +mw_mp_err mw_mp_addmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c) +{ +  mw_mp_err  res; + +  ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); + +  if((res = mw_mp_add(a, b, c)) != MP_OKAY) +    return res; +  if((res = mw_mp_mod(c, m, c)) != MP_OKAY) +    return res; + +  return MP_OKAY; + +} + +/* }}} */ + +/* {{{ mw_mp_submod(a, b, m, c) */ + +/* +  mw_mp_submod(a, b, m, c) + +  Compute c = (a - b) mod m + */ + +mw_mp_err mw_mp_submod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c) +{ +  mw_mp_err  res; + +  ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); + +  if((res = mw_mp_sub(a, b, c)) != MP_OKAY) +    return res; +  if((res = mw_mp_mod(c, m, c)) != MP_OKAY) +    return res; + +  return MP_OKAY; + +} + +/* }}} */ + +/* {{{ mw_mp_mulmod(a, b, m, c) */ + +/* +  mw_mp_mulmod(a, b, m, c) + +  Compute c = (a * b) mod m + */ + +mw_mp_err mw_mp_mulmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c) +{ +  mw_mp_err  res; + +  ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); + +  if((res = mw_mp_mul(a, b, c)) != MP_OKAY) +    return res; +  if((res = mw_mp_mod(c, m, c)) != MP_OKAY) +    return res; + +  return MP_OKAY; + +} + +/* }}} */ + +/* {{{ mw_mp_sqrmod(a, m, c) */ + +#if MP_SQUARE +mw_mp_err mw_mp_sqrmod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c) +{ +  mw_mp_err  res; + +  ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); + +  if((res = mw_mp_sqr(a, c)) != MP_OKAY) +    return res; +  if((res = mw_mp_mod(c, m, c)) != MP_OKAY) +    return res; + +  return MP_OKAY; + +} /* end mw_mp_sqrmod() */ +#endif + +/* }}} */ + +/* {{{ mw_mp_exptmod(a, b, m, c) */ + +/* +  mw_mp_exptmod(a, b, m, c) + +  Compute c = (a ** b) mod m.  Uses a standard square-and-multiply +  method with modular reductions at each step. (This is basically the +  same code as mw_mp_expt(), except for the addition of the reductions) +   +  The modular reductions are done using Barrett's algorithm (see +  s_mw_mp_reduce() below for details) + */ + +mw_mp_err mw_mp_exptmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c) +{ +  mw_mp_int   s, x, mu; +  mw_mp_err   res; +  mw_mp_digit d, *db = DIGITS(b); +  mw_mp_size  ub = USED(b); +  /// Miranda NG adaptation start - MSVC
 +  ///int      dig, bit;
 +  int bit;
 +  mw_mp_size dig; +  /// Miranda NG adaptation end + +  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + +  if(mw_mp_cmw_mp_z(b) < 0 || mw_mp_cmw_mp_z(m) <= 0) +    return MP_RANGE; + +  if((res = mw_mp_init(&s)) != MP_OKAY) +    return res; +  if((res = mw_mp_init_copy(&x, a)) != MP_OKAY) +    goto X; +  if((res = mw_mp_mod(&x, m, &x)) != MP_OKAY || +     (res = mw_mp_init(&mu)) != MP_OKAY) +    goto MU; + +  mw_mp_set(&s, 1); + +  /* mu = b^2k / m */ +  s_mw_mp_add_d(&mu, 1);  +  s_mw_mp_lshd(&mu, 2 * USED(m)); +  if((res = mw_mp_div(&mu, m, &mu, NULL)) != MP_OKAY) +    goto CLEANUP; + +  /* Loop over digits of b in ascending order, except highest order */ +  for(dig = 0; dig < (ub - 1); dig++) { +    d = *db++; + +    /* Loop over the bits of the lower-order digits */ +    for(bit = 0; bit < DIGIT_BIT; bit++) { +      if(d & 1) { +	if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY) +	  goto CLEANUP; +	if((res = s_mw_mp_reduce(&s, m, &mu)) != MP_OKAY) +	  goto CLEANUP; +      } + +      d >>= 1; + +      if((res = s_mw_mp_sqr(&x)) != MP_OKAY) +	goto CLEANUP; +      if((res = s_mw_mp_reduce(&x, m, &mu)) != MP_OKAY) +	goto CLEANUP; +    } +  } + +  /* Now do the last digit... */ +  d = *db; + +  while(d) { +    if(d & 1) { +      if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY) +	goto CLEANUP; +      if((res = s_mw_mp_reduce(&s, m, &mu)) != MP_OKAY) +	goto CLEANUP; +    } + +    d >>= 1; + +    if((res = s_mw_mp_sqr(&x)) != MP_OKAY) +      goto CLEANUP; +    if((res = s_mw_mp_reduce(&x, m, &mu)) != MP_OKAY) +      goto CLEANUP; +  } + +  s_mw_mp_exch(&s, c); + + CLEANUP: +  mw_mp_clear(&mu); + MU: +  mw_mp_clear(&x); + X: +  mw_mp_clear(&s); + +  return res; + +} /* end mw_mp_exptmod() */ + +/* }}} */ + +/* {{{ mw_mp_exptmod_d(a, d, m, c) */ + +mw_mp_err mw_mp_exptmod_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *m, mw_mp_int *c) +{ +  mw_mp_int   s, x; +  mw_mp_err   res; + +  ARGCHK(a != NULL && c != NULL, MP_BADARG); + +  if((res = mw_mp_init(&s)) != MP_OKAY) +    return res; +  if((res = mw_mp_init_copy(&x, a)) != MP_OKAY) +    goto X; + +  mw_mp_set(&s, 1); + +  while(d != 0) { +    if(d & 1) { +      if((res = s_mw_mp_mul(&s, &x)) != MP_OKAY || +	 (res = mw_mp_mod(&s, m, &s)) != MP_OKAY) +	goto CLEANUP; +    } + +    d /= 2; + +    if((res = s_mw_mp_sqr(&x)) != MP_OKAY || +       (res = mw_mp_mod(&x, m, &x)) != MP_OKAY) +      goto CLEANUP; +  } + +  s_mw_mp_exch(&s, c); + +CLEANUP: +  mw_mp_clear(&x); +X: +  mw_mp_clear(&s); + +  return res; + +} /* end mw_mp_exptmod_d() */ + +/* }}} */ +#endif /* if MP_MODARITH */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Comparison functions */ + +/* {{{ mw_mp_cmw_mp_z(a) */ + +/* +  mw_mp_cmw_mp_z(a) + +  Compare a <=> 0.  Returns <0 if a<0, 0 if a=0, >0 if a>0. + */ + +int    mw_mp_cmw_mp_z(mw_mp_int *a) +{ +  if(SIGN(a) == MP_NEG) +    return MP_LT; +  else if(USED(a) == 1 && DIGIT(a, 0) == 0) +    return MP_EQ; +  else +    return MP_GT; + +} /* end mw_mp_cmw_mp_z() */ + +/* }}} */ + +/* {{{ mw_mp_cmw_mp_d(a, d) */ + +/* +  mw_mp_cmw_mp_d(a, d) + +  Compare a <=> d.  Returns <0 if a<d, 0 if a=d, >0 if a>d + */ + +int    mw_mp_cmw_mp_d(mw_mp_int *a, mw_mp_digit d) +{ +  ARGCHK(a != NULL, MP_EQ); + +  if(SIGN(a) == MP_NEG) +    return MP_LT; + +  return s_mw_mp_cmw_mp_d(a, d); + +} /* end mw_mp_cmw_mp_d() */ + +/* }}} */ + +/* {{{ mw_mp_cmp(a, b) */ + +int    mw_mp_cmp(mw_mp_int *a, mw_mp_int *b) +{ +  ARGCHK(a != NULL && b != NULL, MP_EQ); + +  if(SIGN(a) == SIGN(b)) { +    int  mag; + +    if((mag = s_mw_mp_cmp(a, b)) == MP_EQ) +      return MP_EQ; + +    if(SIGN(a) == MP_ZPOS) +      return mag; +    else +      return -mag; + +  } else if(SIGN(a) == MP_ZPOS) { +    return MP_GT; +  } else { +    return MP_LT; +  } + +} /* end mw_mp_cmp() */ + +/* }}} */ + +/* {{{ mw_mp_cmw_mp_mag(a, b) */ + +/* +  mw_mp_cmw_mp_mag(a, b) + +  Compares |a| <=> |b|, and returns an appropriate comparison result + */ + +int    mw_mp_cmw_mp_mag(mw_mp_int *a, mw_mp_int *b) +{ +  ARGCHK(a != NULL && b != NULL, MP_EQ); + +  return s_mw_mp_cmp(a, b); + +} /* end mw_mp_cmw_mp_mag() */ + +/* }}} */ + +/* {{{ mw_mp_cmw_mp_int(a, z) */ + +/* +  This just converts z to an mw_mp_int, and uses the existing comparison +  routines.  This is sort of inefficient, but it's not clear to me how +  frequently this wil get used anyway.  For small positive constants, +  you can always use mw_mp_cmw_mp_d(), and for zero, there is mw_mp_cmw_mp_z(). + */ +int    mw_mp_cmw_mp_int(mw_mp_int *a, long z) +{ +  mw_mp_int  tmp; +  int     out; + +  ARGCHK(a != NULL, MP_EQ); +   +  mw_mp_init(&tmp); mw_mp_set_int(&tmp, z); +  out = mw_mp_cmp(a, &tmp); +  mw_mp_clear(&tmp); + +  return out; + +} /* end mw_mp_cmw_mp_int() */ + +/* }}} */ + +/* {{{ mw_mp_isodd(a) */ + +/* +  mw_mp_isodd(a) + +  Returns a true (non-zero) value if a is odd, false (zero) otherwise. + */ +int    mw_mp_isodd(mw_mp_int *a) +{ +  ARGCHK(a != NULL, 0); + +  return (DIGIT(a, 0) & 1); + +} /* end mw_mp_isodd() */ + +/* }}} */ + +/* {{{ mw_mp_iseven(a) */ + +int    mw_mp_iseven(mw_mp_int *a) +{ +  return !mw_mp_isodd(a); + +} /* end mw_mp_iseven() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Number theoretic functions */ + +#if MP_NUMTH +/* {{{ mw_mp_gcd(a, b, c) */ + +/* +  Like the old mw_mp_gcd() function, except computes the GCD using the +  binary algorithm due to Josef Stein in 1961 (via Knuth). + */ +mw_mp_err mw_mp_gcd(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c) +{ +  mw_mp_err   res; +  mw_mp_int   u, v, t; +  mw_mp_size  k = 0; + +  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + +  if(mw_mp_cmw_mp_z(a) == MP_EQ && mw_mp_cmw_mp_z(b) == MP_EQ) +      return MP_RANGE; +  if(mw_mp_cmw_mp_z(a) == MP_EQ) { +    if((res = mw_mp_copy(b, c)) != MP_OKAY) +      return res; +    SIGN(c) = MP_ZPOS; return MP_OKAY; +  } else if(mw_mp_cmw_mp_z(b) == MP_EQ) { +    if((res = mw_mp_copy(a, c)) != MP_OKAY) +      return res; +    SIGN(c) = MP_ZPOS; return MP_OKAY; +  } + +  if((res = mw_mp_init(&t)) != MP_OKAY) +    return res; +  if((res = mw_mp_init_copy(&u, a)) != MP_OKAY) +    goto U; +  if((res = mw_mp_init_copy(&v, b)) != MP_OKAY) +    goto V; + +  SIGN(&u) = MP_ZPOS; +  SIGN(&v) = MP_ZPOS; + +  /* Divide out common factors of 2 until at least 1 of a, b is even */ +  while(mw_mp_iseven(&u) && mw_mp_iseven(&v)) { +    s_mw_mp_div_2(&u); +    s_mw_mp_div_2(&v); +    ++k; +  } + +  /* Initialize t */ +  if(mw_mp_isodd(&u)) { +    if((res = mw_mp_copy(&v, &t)) != MP_OKAY) +      goto CLEANUP; +     +    /* t = -v */ +    if(SIGN(&v) == MP_ZPOS) +      SIGN(&t) = MP_NEG; +    else +      SIGN(&t) = MP_ZPOS; +     +  } else { +    if((res = mw_mp_copy(&u, &t)) != MP_OKAY) +      goto CLEANUP; + +  } + +  for(;;) { +    while(mw_mp_iseven(&t)) { +      s_mw_mp_div_2(&t); +    } + +    if(mw_mp_cmw_mp_z(&t) == MP_GT) { +      if((res = mw_mp_copy(&t, &u)) != MP_OKAY) +	goto CLEANUP; + +    } else { +      if((res = mw_mp_copy(&t, &v)) != MP_OKAY) +	goto CLEANUP; + +      /* v = -t */ +      if(SIGN(&t) == MP_ZPOS) +	SIGN(&v) = MP_NEG; +      else +	SIGN(&v) = MP_ZPOS; +    } + +    if((res = mw_mp_sub(&u, &v, &t)) != MP_OKAY) +      goto CLEANUP; + +    if(s_mw_mp_cmw_mp_d(&t, 0) == MP_EQ) +      break; +  } + +  s_mw_mp_2expt(&v, k);       /* v = 2^k   */ +  res = mw_mp_mul(&u, &v, c); /* c = u * v */ + + CLEANUP: +  mw_mp_clear(&v); + V: +  mw_mp_clear(&u); + U: +  mw_mp_clear(&t); + +  return res; + +} /* end mw_mp_bgcd() */ + +/* }}} */ + +/* {{{ mw_mp_lcm(a, b, c) */ + +/* We compute the least common multiple using the rule: + +   ab = [a, b](a, b) + +   ... by computing the product, and dividing out the gcd. + */ + +mw_mp_err mw_mp_lcm(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c) +{ +  mw_mp_int  gcd, prod; +  mw_mp_err  res; + +  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + +  /* Set up temporaries */ +  if((res = mw_mp_init(&gcd)) != MP_OKAY) +    return res; +  if((res = mw_mp_init(&prod)) != MP_OKAY) +    goto GCD; + +  if((res = mw_mp_mul(a, b, &prod)) != MP_OKAY) +    goto CLEANUP; +  if((res = mw_mp_gcd(a, b, &gcd)) != MP_OKAY) +    goto CLEANUP; + +  res = mw_mp_div(&prod, &gcd, c, NULL); + + CLEANUP: +  mw_mp_clear(&prod); + GCD: +  mw_mp_clear(&gcd); + +  return res; + +} /* end mw_mp_lcm() */ + +/* }}} */ + +/* {{{ mw_mp_xgcd(a, b, g, x, y) */ + +/* +  mw_mp_xgcd(a, b, g, x, y) + +  Compute g = (a, b) and values x and y satisfying Bezout's identity +  (that is, ax + by = g).  This uses the extended binary GCD algorithm +  based on the Stein algorithm used for mw_mp_gcd() + */ + +mw_mp_err mw_mp_xgcd(mw_mp_int *a, mw_mp_int *b, mw_mp_int *g, mw_mp_int *x, mw_mp_int *y) +{ +  mw_mp_int   gx, xc, yc, u, v, A, B, C, D; +  mw_mp_int  *clean[9]; +  mw_mp_err   res; +  int      last = -1; + +  if(mw_mp_cmw_mp_z(b) == 0) +    return MP_RANGE; + +  /* Initialize all these variables we need */ +  if((res = mw_mp_init(&u)) != MP_OKAY) goto CLEANUP; +  clean[++last] = &u; +  if((res = mw_mp_init(&v)) != MP_OKAY) goto CLEANUP; +  clean[++last] = &v; +  if((res = mw_mp_init(&gx)) != MP_OKAY) goto CLEANUP; +  clean[++last] = &gx; +  if((res = mw_mp_init(&A)) != MP_OKAY) goto CLEANUP; +  clean[++last] = &A; +  if((res = mw_mp_init(&B)) != MP_OKAY) goto CLEANUP; +  clean[++last] = &B; +  if((res = mw_mp_init(&C)) != MP_OKAY) goto CLEANUP; +  clean[++last] = &C; +  if((res = mw_mp_init(&D)) != MP_OKAY) goto CLEANUP; +  clean[++last] = &D; +  if((res = mw_mp_init_copy(&xc, a)) != MP_OKAY) goto CLEANUP; +  clean[++last] = &xc; +  mw_mp_abs(&xc, &xc); +  if((res = mw_mp_init_copy(&yc, b)) != MP_OKAY) goto CLEANUP; +  clean[++last] = &yc; +  mw_mp_abs(&yc, &yc); + +  mw_mp_set(&gx, 1); + +  /* Divide by two until at least one of them is even */ +  while(mw_mp_iseven(&xc) && mw_mp_iseven(&yc)) { +    s_mw_mp_div_2(&xc); +    s_mw_mp_div_2(&yc); +    if((res = s_mw_mp_mul_2(&gx)) != MP_OKAY) +      goto CLEANUP; +  } + +  mw_mp_copy(&xc, &u); +  mw_mp_copy(&yc, &v); +  mw_mp_set(&A, 1); mw_mp_set(&D, 1); + +  /* Loop through binary GCD algorithm */ +  for(;;) { +    while(mw_mp_iseven(&u)) { +      s_mw_mp_div_2(&u); + +      if(mw_mp_iseven(&A) && mw_mp_iseven(&B)) { +	s_mw_mp_div_2(&A); s_mw_mp_div_2(&B); +      } else { +	if((res = mw_mp_add(&A, &yc, &A)) != MP_OKAY) goto CLEANUP; +	s_mw_mp_div_2(&A); +	if((res = mw_mp_sub(&B, &xc, &B)) != MP_OKAY) goto CLEANUP; +	s_mw_mp_div_2(&B); +      } +    } + +    while(mw_mp_iseven(&v)) { +      s_mw_mp_div_2(&v); + +      if(mw_mp_iseven(&C) && mw_mp_iseven(&D)) { +	s_mw_mp_div_2(&C); s_mw_mp_div_2(&D); +      } else { +	if((res = mw_mp_add(&C, &yc, &C)) != MP_OKAY) goto CLEANUP; +	s_mw_mp_div_2(&C); +	if((res = mw_mp_sub(&D, &xc, &D)) != MP_OKAY) goto CLEANUP; +	s_mw_mp_div_2(&D); +      } +    } + +    if(mw_mp_cmp(&u, &v) >= 0) { +      if((res = mw_mp_sub(&u, &v, &u)) != MP_OKAY) goto CLEANUP; +      if((res = mw_mp_sub(&A, &C, &A)) != MP_OKAY) goto CLEANUP; +      if((res = mw_mp_sub(&B, &D, &B)) != MP_OKAY) goto CLEANUP; + +    } else { +      if((res = mw_mp_sub(&v, &u, &v)) != MP_OKAY) goto CLEANUP; +      if((res = mw_mp_sub(&C, &A, &C)) != MP_OKAY) goto CLEANUP; +      if((res = mw_mp_sub(&D, &B, &D)) != MP_OKAY) goto CLEANUP; + +    } + +    /* If we're done, copy results to output */ +    if(mw_mp_cmw_mp_z(&u) == 0) { +      if(x) +	if((res = mw_mp_copy(&C, x)) != MP_OKAY) goto CLEANUP; + +      if(y) +	if((res = mw_mp_copy(&D, y)) != MP_OKAY) goto CLEANUP; +       +      if(g) +	if((res = mw_mp_mul(&gx, &v, g)) != MP_OKAY) goto CLEANUP; + +      break; +    } +  } + + CLEANUP: +  while(last >= 0) +    mw_mp_clear(clean[last--]); + +  return res; + +} /* end mw_mp_xgcd() */ + +/* }}} */ + +/* {{{ mw_mp_invmod(a, m, c) */ + +/* +  mw_mp_invmod(a, m, c) + +  Compute c = a^-1 (mod m), if there is an inverse for a (mod m). +  This is equivalent to the question of whether (a, m) = 1.  If not, +  MP_UNDEF is returned, and there is no inverse. + */ + +mw_mp_err mw_mp_invmod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c) +{ +  mw_mp_int  g, x; +  mw_mp_sign sa; +  mw_mp_err  res; + +  ARGCHK(a && m && c, MP_BADARG); + +  if(mw_mp_cmw_mp_z(a) == 0 || mw_mp_cmw_mp_z(m) == 0) +    return MP_RANGE; + +  sa = SIGN(a); + +  if((res = mw_mp_init(&g)) != MP_OKAY) +    return res; +  if((res = mw_mp_init(&x)) != MP_OKAY) +    goto X; + +  if((res = mw_mp_xgcd(a, m, &g, &x, NULL)) != MP_OKAY) +    goto CLEANUP; + +  if(mw_mp_cmw_mp_d(&g, 1) != MP_EQ) { +    res = MP_UNDEF; +    goto CLEANUP; +  } + +  res = mw_mp_mod(&x, m, c); +  SIGN(c) = sa; + +CLEANUP: +  mw_mp_clear(&x); +X: +  mw_mp_clear(&g); + +  return res; + +} /* end mw_mp_invmod() */ + +/* }}} */ +#endif /* if MP_NUMTH */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ mw_mp_print(mp, ofp) */ + +#if MP_IOFUNC +/* +  mw_mp_print(mp, ofp) + +  Print a textual representation of the given mw_mp_int on the output +  stream 'ofp'.  Output is generated using the internal radix. + */ + +void   mw_mp_print(mw_mp_int *mp, FILE *ofp) +{ +  int   ix; + +  if(mp == NULL || ofp == NULL) +    return; + +  fputc((SIGN(mp) == MP_NEG) ? '-' : '+', ofp); + +  for(ix = USED(mp) - 1; ix >= 0; ix--) { +    fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix)); +  } + +} /* end mw_mp_print() */ + +#endif /* if MP_IOFUNC */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ More I/O Functions */ + +/* {{{ mw_mp_read_signed_bin(mp, str, len) */ + +/*  +   mw_mp_read_signed_bin(mp, str, len) + +   Read in a raw value (base 256) into the given mw_mp_int + */ + +mw_mp_err  mw_mp_read_signed_bin(mw_mp_int *mp, unsigned char *str, int len) +{ +  mw_mp_err         res; + +  ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); + +  if((res = mw_mp_read_unsigned_bin(mp, str + 1, len - 1)) == MP_OKAY) { +    /* Get sign from first byte */ +    if(str[0]) +      SIGN(mp) = MP_NEG; +    else +      SIGN(mp) = MP_ZPOS; +  } + +  return res; + +} /* end mw_mp_read_signed_bin() */ + +/* }}} */ + +/* {{{ mw_mp_signed_bin_size(mp) */ + +int    mw_mp_signed_bin_size(mw_mp_int *mp) +{ +  ARGCHK(mp != NULL, 0); + +  return mw_mp_unsigned_bin_size(mp) + 1; + +} /* end mw_mp_signed_bin_size() */ + +/* }}} */ + +/* {{{ mw_mp_to_signed_bin(mp, str) */ + +mw_mp_err mw_mp_to_signed_bin(mw_mp_int *mp, unsigned char *str) +{ +  ARGCHK(mp != NULL && str != NULL, MP_BADARG); + +  /* Caller responsible for allocating enough memory (use mw_mp_raw_size(mp)) */ +  str[0] = (char)SIGN(mp); + +  return mw_mp_to_unsigned_bin(mp, str + 1); + +} /* end mw_mp_to_signed_bin() */ + +/* }}} */ + +/* {{{ mw_mp_read_unsigned_bin(mp, str, len) */ + +/* +  mw_mp_read_unsigned_bin(mp, str, len) + +  Read in an unsigned value (base 256) into the given mw_mp_int + */ + +mw_mp_err  mw_mp_read_unsigned_bin(mw_mp_int *mp, unsigned char *str, int len) +{ +  int     ix; +  mw_mp_err  res; + +  ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); + +  mw_mp_zero(mp); + +  for(ix = 0; ix < len; ix++) { +    if((res = s_mw_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) +      return res; + +    if((res = mw_mp_add_d(mp, str[ix], mp)) != MP_OKAY) +      return res; +  } +   +  return MP_OKAY; +   +} /* end mw_mp_read_unsigned_bin() */ + +/* }}} */ + +/* {{{ mw_mp_unsigned_bin_size(mp) */ + +int     mw_mp_unsigned_bin_size(mw_mp_int *mp)  +{ +  mw_mp_digit   topdig; +  int        count; + +  ARGCHK(mp != NULL, 0); + +  /* Special case for the value zero */ +  if(USED(mp) == 1 && DIGIT(mp, 0) == 0) +    return 1; + +  count = (USED(mp) - 1) * sizeof(mw_mp_digit); +  topdig = DIGIT(mp, USED(mp) - 1); + +  while(topdig != 0) { +    ++count; +    topdig >>= CHAR_BIT; +  } + +  return count; + +} /* end mw_mp_unsigned_bin_size() */ + +/* }}} */ + +/* {{{ mw_mp_to_unsigned_bin(mp, str) */ + +mw_mp_err mw_mp_to_unsigned_bin(mw_mp_int *mp, unsigned char *str) +{ +  mw_mp_digit      *dp, *end, d; +  unsigned char *spos; + +  ARGCHK(mp != NULL && str != NULL, MP_BADARG); + +  dp = DIGITS(mp); +  end = dp + USED(mp) - 1; +  spos = str; + +  /* Special case for zero, quick test */ +  if(dp == end && *dp == 0) { +    *str = '\0'; +    return MP_OKAY; +  } + +  /* Generate digits in reverse order */ +  while(dp < end) { +    int      ix; + +    d = *dp; +    for(ix = 0; ix < sizeof(mw_mp_digit); ++ix) { +      *spos = d & UCHAR_MAX; +      d >>= CHAR_BIT; +      ++spos; +    } + +    ++dp; +  } + +  /* Now handle last digit specially, high order zeroes are not written */ +  d = *end; +  while(d != 0) { +    *spos = d & UCHAR_MAX; +    d >>= CHAR_BIT; +    ++spos; +  } + +  /* Reverse everything to get digits in the correct order */ +  while(--spos > str) { +    unsigned char t = *str; +    *str = *spos; +    *spos = t; + +    ++str; +  } + +  return MP_OKAY; + +} /* end mw_mp_to_unsigned_bin() */ + +/* }}} */ + +/* {{{ mw_mp_count_bits(mp) */ + +int    mw_mp_count_bits(mw_mp_int *mp) +{ +  int      len; +  mw_mp_digit d; + +  ARGCHK(mp != NULL, MP_BADARG); + +  len = DIGIT_BIT * (USED(mp) - 1); +  d = DIGIT(mp, USED(mp) - 1); + +  while(d != 0) { +    ++len; +    d >>= 1; +  } + +  return len; +   +} /* end mw_mp_count_bits() */ + +/* }}} */ + +/* {{{ mw_mp_read_radix(mp, str, radix) */ + +/* +  mw_mp_read_radix(mp, str, radix) + +  Read an integer from the given string, and set mp to the resulting +  value.  The input is presumed to be in base 10.  Leading non-digit +  characters are ignored, and the function reads until a non-digit +  character or the end of the string. + */ + +mw_mp_err  mw_mp_read_radix(mw_mp_int *mp, unsigned char *str, int radix) +{ +  int     ix = 0, val = 0; +  mw_mp_err  res; +  mw_mp_sign sig = MP_ZPOS; + +  ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX,  +	 MP_BADARG); + +  mw_mp_zero(mp); + +  /* Skip leading non-digit characters until a digit or '-' or '+' */ +  while(str[ix] &&  +	(s_mw_mp_tovalue(str[ix], radix) < 0) &&  +	str[ix] != '-' && +	str[ix] != '+') { +    ++ix; +  } + +  if(str[ix] == '-') { +    sig = MP_NEG; +    ++ix; +  } else if(str[ix] == '+') { +    sig = MP_ZPOS; /* this is the default anyway... */ +    ++ix; +  } + +  while((val = s_mw_mp_tovalue(str[ix], radix)) >= 0) { +    if((res = s_mw_mp_mul_d(mp, radix)) != MP_OKAY) +      return res; +    if((res = s_mw_mp_add_d(mp, val)) != MP_OKAY) +      return res; +    ++ix; +  } + +  if(s_mw_mp_cmw_mp_d(mp, 0) == MP_EQ) +    SIGN(mp) = MP_ZPOS; +  else +    SIGN(mp) = sig; + +  return MP_OKAY; + +} /* end mw_mp_read_radix() */ + +/* }}} */ + +/* {{{ mw_mp_radix_size(mp, radix) */ + +int    mw_mp_radix_size(mw_mp_int *mp, int radix) +{ +  int  len; +  ARGCHK(mp != NULL, 0); + +  len = s_mw_mp_outlen(mw_mp_count_bits(mp), radix) + 1; /* for NUL terminator */ + +  if(mw_mp_cmw_mp_z(mp) < 0) +    ++len; /* for sign */ + +  return len; + +} /* end mw_mp_radix_size() */ + +/* }}} */ + +/* {{{ mw_mp_value_radix_size(num, qty, radix) */ + +/* num = number of digits +   qty = number of bits per digit +   radix = target base +    +   Return the number of digits in the specified radix that would be +   needed to express 'num' digits of 'qty' bits each. + */ +int    mw_mp_value_radix_size(int num, int qty, int radix) +{ +  ARGCHK(num >= 0 && qty > 0 && radix >= 2 && radix <= MAX_RADIX, 0); + +  return s_mw_mp_outlen(num * qty, radix); + +} /* end mw_mp_value_radix_size() */ + +/* }}} */ + +/* {{{ mw_mp_toradix(mp, str, radix) */ + +mw_mp_err mw_mp_toradix(mw_mp_int *mp, unsigned char *str, int radix) +{ +  int  ix, pos = 0; + +  ARGCHK(mp != NULL && str != NULL, MP_BADARG); +  ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE); + +  if(mw_mp_cmw_mp_z(mp) == MP_EQ) { +    str[0] = '0'; +    str[1] = '\0'; +  } else { +    mw_mp_err   res; +    mw_mp_int   tmp; +    mw_mp_sign  sgn; +    mw_mp_digit rem, rdx = (mw_mp_digit)radix; +    char     ch; + +    if((res = mw_mp_init_copy(&tmp, mp)) != MP_OKAY) +      return res; + +    /* Save sign for later, and take absolute value */ +    sgn = SIGN(&tmp); SIGN(&tmp) = MP_ZPOS; + +    /* Generate output digits in reverse order      */ +    while(mw_mp_cmw_mp_z(&tmp) != 0) { +      if((res = s_mw_mp_div_d(&tmp, rdx, &rem)) != MP_OKAY) { +	mw_mp_clear(&tmp); +	return res; +      } + +      /* Generate digits, use capital letters */ +      ch = s_mw_mp_todigit(rem, radix, 0); + +      str[pos++] = ch; +    } + +    /* Add - sign if original value was negative */ +    if(sgn == MP_NEG) +      str[pos++] = '-'; + +    /* Add trailing NUL to end the string        */ +    str[pos--] = '\0'; + +    /* Reverse the digits and sign indicator     */ +    ix = 0; +    while(ix < pos) { +      char tmp = str[ix]; + +      str[ix] = str[pos]; +      str[pos] = tmp; +      ++ix; +      --pos; +    } +     +    mw_mp_clear(&tmp); +  } + +  return MP_OKAY; + +} /* end mw_mp_toradix() */ + +/* }}} */ + +/* {{{ mw_mp_char2value(ch, r) */ + +int    mw_mp_char2value(char ch, int r) +{ +  return s_mw_mp_tovalue(ch, r); + +} /* end mw_mp_tovalue() */ + +/* }}} */ + +/* }}} */ + +/* {{{ mw_mp_strerror(ec) */ + +/* +  mw_mp_strerror(ec) + +  Return a string describing the meaning of error code 'ec'.  The +  string returned is allocated in static memory, so the caller should +  not attempt to modify or free the memory associated with this +  string. + */ +const char  *mw_mp_strerror(mw_mp_err ec) +{ +  int   aec = (ec < 0) ? -ec : ec; + +  /* Code values are negative, so the senses of these comparisons +     are accurate */ +  if(ec < MP_LAST_CODE || ec > MP_OKAY) { +    return mw_mp_err_string[0];  /* unknown error code */ +  } else { +    return mw_mp_err_string[aec + 1]; +  } + +} /* end mw_mp_strerror() */ + +/* }}} */ + +/*========================================================================*/ +/*------------------------------------------------------------------------*/ +/* Static function definitions (internal use only)                        */ + +/* {{{ Memory management */ + +/* {{{ s_mw_mp_grow(mp, min) */ + +/* Make sure there are at least 'min' digits allocated to mp              */ +mw_mp_err   s_mw_mp_grow(mw_mp_int *mp, mw_mp_size min) +{ +  if(min > ALLOC(mp)) { +    mw_mp_digit   *tmp; + +    /* Set min to next nearest default precision block size */ +    min = ((min + (s_mw_mp_defprec - 1)) / s_mw_mp_defprec) * s_mw_mp_defprec; + +    if((tmp = s_mw_mp_alloc(min, sizeof(mw_mp_digit))) == NULL) +      return MP_MEM; + +    s_mw_mp_copy(DIGITS(mp), tmp, USED(mp)); + +#if MP_CRYPTO +    s_mw_mp_setz(DIGITS(mp), ALLOC(mp)); +#endif +    s_mw_mp_free(DIGITS(mp)); +    DIGITS(mp) = tmp; +    ALLOC(mp) = min; +  } + +  return MP_OKAY; + +} /* end s_mw_mp_grow() */ + +/* }}} */ + +/* {{{ s_mw_mp_pad(mp, min) */ + +/* Make sure the used size of mp is at least 'min', growing if needed     */ +mw_mp_err   s_mw_mp_pad(mw_mp_int *mp, mw_mp_size min) +{ +  if(min > USED(mp)) { +    mw_mp_err  res; + +    /* Make sure there is room to increase precision  */ +    if(min > ALLOC(mp) && (res = s_mw_mp_grow(mp, min)) != MP_OKAY) +      return res; + +    /* Increase precision; should already be 0-filled */ +    USED(mp) = min; +  } + +  return MP_OKAY; + +} /* end s_mw_mp_pad() */ + +/* }}} */ + +/* {{{ s_mw_mp_setz(dp, count) */ + +#if MP_MACRO == 0 +/* Set 'count' digits pointed to by dp to be zeroes                       */ +void s_mw_mp_setz(mw_mp_digit *dp, mw_mp_size count) +{ +#if MP_MEMSET == 0 +  int  ix; + +  for(ix = 0; ix < count; ix++) +    dp[ix] = 0; +#else +  memset(dp, 0, count * sizeof(mw_mp_digit)); +#endif + +} /* end s_mw_mp_setz() */ +#endif + +/* }}} */ + +/* {{{ s_mw_mp_copy(sp, dp, count) */ + +#if MP_MACRO == 0 +/* Copy 'count' digits from sp to dp                                      */ +void s_mw_mp_copy(mw_mp_digit *sp, mw_mp_digit *dp, mw_mp_size count) +{ +#if MP_MEMCPY == 0 +  int  ix; + +  for(ix = 0; ix < count; ix++) +    dp[ix] = sp[ix]; +#else +  memcpy(dp, sp, count * sizeof(mw_mp_digit)); +#endif + +} /* end s_mw_mp_copy() */ +#endif + +/* }}} */ + +/* {{{ s_mw_mp_alloc(nb, ni) */ + +#if MP_MACRO == 0 +/* Allocate ni records of nb bytes each, and return a pointer to that     */ +void    *s_mw_mp_alloc(size_t nb, size_t ni) +{ +  return calloc(nb, ni); + +} /* end s_mw_mp_alloc() */ +#endif + +/* }}} */ + +/* {{{ s_mw_mp_free(ptr) */ + +#if MP_MACRO == 0 +/* Free the memory pointed to by ptr                                      */ +void     s_mw_mp_free(void *ptr) +{ +  if(ptr) +    free(ptr); + +} /* end s_mw_mp_free() */ +#endif + +/* }}} */ + +/* {{{ s_mw_mp_clamp(mp) */ + +/* Remove leading zeroes from the given value                             */ +void     s_mw_mp_clamp(mw_mp_int *mp) +{ +  mw_mp_size   du = USED(mp); +  mw_mp_digit *zp = DIGITS(mp) + du - 1; + +  while(du > 1 && !*zp--) +    --du; + +  if(du == 1 && *zp == 0) +    SIGN(mp) = MP_ZPOS; + +  USED(mp) = du; + +} /* end s_mw_mp_clamp() */ + + +/* }}} */ + +/* {{{ s_mw_mp_exch(a, b) */ + +/* Exchange the data for a and b; (b, a) = (a, b)                         */ +void     s_mw_mp_exch(mw_mp_int *a, mw_mp_int *b) +{ +  mw_mp_int   tmp; + +  tmp = *a; +  *a = *b; +  *b = tmp; + +} /* end s_mw_mp_exch() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Arithmetic helpers */ + +/* {{{ s_mw_mp_lshd(mp, p) */ + +/*  +   Shift mp leftward by p digits, growing if needed, and zero-filling +   the in-shifted digits at the right end.  This is a convenient +   alternative to multiplication by powers of the radix + */    + +mw_mp_err   s_mw_mp_lshd(mw_mp_int *mp, mw_mp_size p) +{ +  mw_mp_err   res; +  mw_mp_size  pos; +  mw_mp_digit *dp; +  int     ix; + +  if(p == 0) +    return MP_OKAY; + +  if((res = s_mw_mp_pad(mp, USED(mp) + p)) != MP_OKAY) +    return res; + +  pos = USED(mp) - 1; +  dp = DIGITS(mp); + +  /* Shift all the significant figures over as needed */ +  /// Miranda NG adaptation start - MSVC +  ///for(ix = pos - p; ix >= 0; ix--)  +  for(ix = (int)(pos - p); ix >= 0; ix--)  +  /// Miranda NG adaptation end +    dp[ix + p] = dp[ix]; + +  /* Fill the bottom digits with zeroes */ +  /// Miranda NG adaptation start - MSVC +  ///for(ix = 0; ix < p; ix++) +  for(ix = 0; ix < (int)p; ix++)  +  /// Miranda NG adaptation end +    dp[ix] = 0; + +  return MP_OKAY; + +} /* end s_mw_mp_lshd() */ + +/* }}} */ + +/* {{{ s_mw_mp_rshd(mp, p) */ + +/*  +   Shift mp rightward by p digits.  Maintains the invariant that +   digits above the precision are all zero.  Digits shifted off the +   end are lost.  Cannot fail. + */ + +void     s_mw_mp_rshd(mw_mp_int *mp, mw_mp_size p) +{ +  mw_mp_size  ix; +  mw_mp_digit *dp; + +  if(p == 0) +    return; + +  /* Shortcut when all digits are to be shifted off */ +  if(p >= USED(mp)) { +    s_mw_mp_setz(DIGITS(mp), ALLOC(mp)); +    USED(mp) = 1; +    SIGN(mp) = MP_ZPOS; +    return; +  } + +  /* Shift all the significant figures over as needed */ +  dp = DIGITS(mp); +  for(ix = p; ix < USED(mp); ix++) +    dp[ix - p] = dp[ix]; + +  /* Fill the top digits with zeroes */ +  ix -= p; +  while(ix < USED(mp)) +    dp[ix++] = 0; + +  /* Strip off any leading zeroes    */ +  s_mw_mp_clamp(mp); + +} /* end s_mw_mp_rshd() */ + +/* }}} */ + +/* {{{ s_mw_mp_div_2(mp) */ + +/* Divide by two -- take advantage of radix properties to do it fast      */ +void     s_mw_mp_div_2(mw_mp_int *mp) +{ +  s_mw_mp_div_2d(mp, 1); + +} /* end s_mw_mp_div_2() */ + +/* }}} */ + +/* {{{ s_mw_mp_mul_2(mp) */ + +mw_mp_err s_mw_mp_mul_2(mw_mp_int *mp) +{ +  /// Miranda NG adaptation start - MSVC +  //int      ix; +  mw_mp_size ix; +  /// Miranda NG adaptation end +  mw_mp_digit kin = 0, kout, *dp = DIGITS(mp); +  mw_mp_err   res; + +  /* Shift digits leftward by 1 bit */ +  for(ix = 0; ix < USED(mp); ix++) { +    kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1; +    dp[ix] = (dp[ix] << 1) | kin; + +    kin = kout; +  } + +  /* Deal with rollover from last digit */ +  if(kin) { +    if(ix >= ALLOC(mp)) { +      if((res = s_mw_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY) +	return res; +      dp = DIGITS(mp); +    } + +    dp[ix] = kin; +    USED(mp) += 1; +  } + +  return MP_OKAY; + +} /* end s_mw_mp_mul_2() */ + +/* }}} */ + +/* {{{ s_mw_mp_mod_2d(mp, d) */ + +/* +  Remainder the integer by 2^d, where d is a number of bits.  This +  amounts to a bitwise AND of the value, and does not require the full +  division code + */ +void     s_mw_mp_mod_2d(mw_mp_int *mp, mw_mp_digit d) +{ +  unsigned int  ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT); +  unsigned int  ix; +  mw_mp_digit      dmask, *dp = DIGITS(mp); + +  if(ndig >= USED(mp)) +    return; + +  /* Flush all the bits above 2^d in its digit */ +  dmask = (1 << nbit) - 1; +  dp[ndig] &= dmask; + +  /* Flush all digits above the one with 2^d in it */ +  for(ix = ndig + 1; ix < USED(mp); ix++) +    dp[ix] = 0; + +  s_mw_mp_clamp(mp); + +} /* end s_mw_mp_mod_2d() */ + +/* }}} */ + +/* {{{ s_mw_mp_mul_2d(mp, d) */ + +/* +  Multiply by the integer 2^d, where d is a number of bits.  This +  amounts to a bitwise shift of the value, and does not require the +  full multiplication code. + */ +mw_mp_err    s_mw_mp_mul_2d(mw_mp_int *mp, mw_mp_digit d) +{ +  mw_mp_err   res; +  mw_mp_digit save, next, mask, *dp; +  mw_mp_size  used; +  /// Miranda NG adaptation start - MSVC +  ///int      ix; +  mw_mp_size ix; +  /// Miranda NG adaptation end + +  if((res = s_mw_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY) +    return res; + +  dp = DIGITS(mp); used = USED(mp); +  d %= DIGIT_BIT; + +  mask = (1 << d) - 1; + +  /* If the shift requires another digit, make sure we've got one to +     work with */ +  if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) { +    if((res = s_mw_mp_grow(mp, used + 1)) != MP_OKAY) +      return res; +    dp = DIGITS(mp); +  } + +  /* Do the shifting... */ +  save = 0; +  for(ix = 0; ix < used; ix++) { +    next = (dp[ix] >> (DIGIT_BIT - d)) & mask; +    dp[ix] = (dp[ix] << d) | save; +    save = next; +  } + +  /* If, at this point, we have a nonzero carryout into the next +     digit, we'll increase the size by one digit, and store it... +   */ +  if(save) { +    dp[used] = save; +    USED(mp) += 1; +  } + +  s_mw_mp_clamp(mp); +  return MP_OKAY; + +} /* end s_mw_mp_mul_2d() */ + +/* }}} */ + +/* {{{ s_mw_mp_div_2d(mp, d) */ + +/* +  Divide the integer by 2^d, where d is a number of bits.  This +  amounts to a bitwise shift of the value, and does not require the +  full division code (used in Barrett reduction, see below) + */ +void     s_mw_mp_div_2d(mw_mp_int *mp, mw_mp_digit d) +{ +  int       ix; +  mw_mp_digit  save, next, mask, *dp = DIGITS(mp); + +  s_mw_mp_rshd(mp, d / DIGIT_BIT); +  d %= DIGIT_BIT; + +  mask = (1 << d) - 1; + +  save = 0; +  for(ix = USED(mp) - 1; ix >= 0; ix--) { +    next = dp[ix] & mask; +    dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d)); +    save = next; +  } + +  s_mw_mp_clamp(mp); + +} /* end s_mw_mp_div_2d() */ + +/* }}} */ + +/* {{{ s_mw_mp_norm(a, b) */ + +/* +  s_mw_mp_norm(a, b) + +  Normalize a and b for division, where b is the divisor.  In order +  that we might make good guesses for quotient digits, we want the +  leading digit of b to be at least half the radix, which we +  accomplish by multiplying a and b by a constant.  This constant is +  returned (so that it can be divided back out of the remainder at the +  end of the division process). + +  We multiply by the smallest power of 2 that gives us a leading digit +  at least half the radix.  By choosing a power of 2, we simplify the  +  multiplication and division steps to simple shifts. + */ +mw_mp_digit s_mw_mp_norm(mw_mp_int *a, mw_mp_int *b) +{ +  mw_mp_digit  t, d = 0; + +  t = DIGIT(b, USED(b) - 1); +  while(t < (RADIX / 2)) { +    t <<= 1; +    ++d; +  } +     +  if(d != 0) { +    s_mw_mp_mul_2d(a, d); +    s_mw_mp_mul_2d(b, d); +  } + +  return d; + +} /* end s_mw_mp_norm() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive digit arithmetic */ + +/* {{{ s_mw_mp_add_d(mp, d) */ + +/* Add d to |mp| in place                                                 */ +mw_mp_err   s_mw_mp_add_d(mw_mp_int *mp, mw_mp_digit d)    /* unsigned digit addition */ +{ +  mw_mp_word   w, k = 0; +  mw_mp_size   ix = 1, used = USED(mp); +  mw_mp_digit *dp = DIGITS(mp); + +  w = dp[0] + d; +  dp[0] = ACCUM(w); +  k = CARRYOUT(w); + +  while(ix < used && k) { +    w = dp[ix] + k; +    dp[ix] = ACCUM(w); +    k = CARRYOUT(w); +    ++ix; +  } + +  if(k != 0) { +    mw_mp_err  res; + +    if((res = s_mw_mp_pad(mp, USED(mp) + 1)) != MP_OKAY) +      return res; + +    DIGIT(mp, ix) = k; +  } + +  return MP_OKAY; + +} /* end s_mw_mp_add_d() */ + +/* }}} */ + +/* {{{ s_mw_mp_sub_d(mp, d) */ + +/* Subtract d from |mp| in place, assumes |mp| > d                        */ +mw_mp_err   s_mw_mp_sub_d(mw_mp_int *mp, mw_mp_digit d)    /* unsigned digit subtract */ +{ +  mw_mp_word   w, b = 0; +  mw_mp_size   ix = 1, used = USED(mp); +  mw_mp_digit *dp = DIGITS(mp); + +  /* Compute initial subtraction    */ +  w = (RADIX + dp[0]) - d; +  b = CARRYOUT(w) ? 0 : 1; +  dp[0] = ACCUM(w); + +  /* Propagate borrows leftward     */ +  while(b && ix < used) { +    w = (RADIX + dp[ix]) - b; +    b = CARRYOUT(w) ? 0 : 1; +    dp[ix] = ACCUM(w); +    ++ix; +  } + +  /* Remove leading zeroes          */ +  s_mw_mp_clamp(mp); + +  /* If we have a borrow out, it's a violation of the input invariant */ +  if(b) +    return MP_RANGE; +  else +    return MP_OKAY; + +} /* end s_mw_mp_sub_d() */ + +/* }}} */ + +/* {{{ s_mw_mp_mul_d(a, d) */ + +/* Compute a = a * d, single digit multiplication                         */ +mw_mp_err   s_mw_mp_mul_d(mw_mp_int *a, mw_mp_digit d) +{ +  mw_mp_word w, k = 0; +  mw_mp_size ix, max; +  mw_mp_err  res; +  mw_mp_digit *dp = DIGITS(a); + +  /* +    Single-digit multiplication will increase the precision of the +    output by at most one digit.  However, we can detect when this +    will happen -- if the high-order digit of a, times d, gives a +    two-digit result, then the precision of the result will increase; +    otherwise it won't.  We use this fact to avoid calling s_mw_mp_pad() +    unless absolutely necessary. +   */ +  max = USED(a); +  w = dp[max - 1] * d; +  if(CARRYOUT(w) != 0) { +    if((res = s_mw_mp_pad(a, max + 1)) != MP_OKAY) +      return res; +    dp = DIGITS(a); +  } + +  for(ix = 0; ix < max; ix++) { +    w = (dp[ix] * d) + k; +    dp[ix] = ACCUM(w); +    k = CARRYOUT(w); +  } + +  /* If there is a precision increase, take care of it here; the above +     test guarantees we have enough storage to do this safely. +   */ +  if(k) { +    dp[max] = k;  +    USED(a) = max + 1; +  } + +  s_mw_mp_clamp(a); + +  return MP_OKAY; +   +} /* end s_mw_mp_mul_d() */ + +/* }}} */ + +/* {{{ s_mw_mp_div_d(mp, d, r) */ + +/* +  s_mw_mp_div_d(mp, d, r) + +  Compute the quotient mp = mp / d and remainder r = mp mod d, for a +  single digit d.  If r is null, the remainder will be discarded. + */ + +mw_mp_err   s_mw_mp_div_d(mw_mp_int *mp, mw_mp_digit d, mw_mp_digit *r) +{ +  mw_mp_word   w = 0, t; +  mw_mp_int    quot; +  mw_mp_err    res; +  mw_mp_digit *dp = DIGITS(mp), *qp; +  int       ix; + +  if(d == 0) +    return MP_RANGE; + +  /* Make room for the quotient */ +  if((res = mw_mp_init_size(", USED(mp))) != MP_OKAY) +    return res; + +  USED(") = USED(mp); /* so clamping will work below */ +  qp = DIGITS("); + +  /* Divide without subtraction */ +  for(ix = USED(mp) - 1; ix >= 0; ix--) { +    w = (w << DIGIT_BIT) | dp[ix]; + +    if(w >= d) { +      t = w / d; +      w = w % d; +    } else { +      t = 0; +    } + +    qp[ix] = t; +  } + +  /* Deliver the remainder, if desired */ +  if(r) +    *r = w; + +  s_mw_mp_clamp("); +  mw_mp_exch(", mp); +  mw_mp_clear("); + +  return MP_OKAY; + +} /* end s_mw_mp_div_d() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive full arithmetic */ + +/* {{{ s_mw_mp_add(a, b) */ + +/* Compute a = |a| + |b|                                                  */ +mw_mp_err   s_mw_mp_add(mw_mp_int *a, mw_mp_int *b)        /* magnitude addition      */ +{ +  mw_mp_word   w = 0; +  mw_mp_digit *pa, *pb; +  mw_mp_size   ix, used = USED(b); +  mw_mp_err    res; + +  /* Make sure a has enough precision for the output value */ +  if((used > USED(a)) && (res = s_mw_mp_pad(a, used)) != MP_OKAY) +    return res; + +  /* +    Add up all digits up to the precision of b.  If b had initially +    the same precision as a, or greater, we took care of it by the +    padding step above, so there is no problem.  If b had initially +    less precision, we'll have to make sure the carry out is duly +    propagated upward among the higher-order digits of the sum. +   */ +  pa = DIGITS(a); +  pb = DIGITS(b); +  for(ix = 0; ix < used; ++ix) { +    w += *pa + *pb++; +    *pa++ = ACCUM(w); +    w = CARRYOUT(w); +  } + +  /* If we run out of 'b' digits before we're actually done, make +     sure the carries get propagated upward...   +   */ +  used = USED(a); +  while(w && ix < used) { +    w += *pa; +    *pa++ = ACCUM(w); +    w = CARRYOUT(w); +    ++ix; +  } + +  /* If there's an overall carry out, increase precision and include +     it.  We could have done this initially, but why touch the memory +     allocator unless we're sure we have to? +   */ +  if(w) { +    if((res = s_mw_mp_pad(a, used + 1)) != MP_OKAY) +      return res; + +    DIGIT(a, ix) = w;  /* pa may not be valid after s_mw_mp_pad() call */ +  } + +  return MP_OKAY; + +} /* end s_mw_mp_add() */ + +/* }}} */ + +/* {{{ s_mw_mp_sub(a, b) */ + +/* Compute a = |a| - |b|, assumes |a| >= |b|                              */ +mw_mp_err   s_mw_mp_sub(mw_mp_int *a, mw_mp_int *b)        /* magnitude subtract      */ +{ +  mw_mp_word   w = 0; +  mw_mp_digit *pa, *pb; +  mw_mp_size   ix, used = USED(b); + +  /* +    Subtract and propagate borrow.  Up to the precision of b, this +    accounts for the digits of b; after that, we just make sure the +    carries get to the right place.  This saves having to pad b out to +    the precision of a just to make the loops work right... +   */ +  pa = DIGITS(a); +  pb = DIGITS(b); + +  for(ix = 0; ix < used; ++ix) { +    w = (RADIX + *pa) - w - *pb++; +    *pa++ = ACCUM(w); +    w = CARRYOUT(w) ? 0 : 1; +  } + +  used = USED(a); +  while(ix < used) { +    w = RADIX + *pa - w; +    *pa++ = ACCUM(w); +    w = CARRYOUT(w) ? 0 : 1; +    ++ix; +  } + +  /* Clobber any leading zeroes we created    */ +  s_mw_mp_clamp(a); + +  /*  +     If there was a borrow out, then |b| > |a| in violation +     of our input invariant.  We've already done the work, +     but we'll at least complain about it... +   */ +  if(w) +    return MP_RANGE; +  else +    return MP_OKAY; + +} /* end s_mw_mp_sub() */ + +/* }}} */ + +/* {{{ s_mw_mp_mul(a, b) */ + +/* Compute a = |a| * |b|                                                  */ +mw_mp_err   s_mw_mp_mul(mw_mp_int *a, mw_mp_int *b) +{ +  mw_mp_word   w, k = 0; +  mw_mp_int    tmp; +  mw_mp_err    res; +  mw_mp_size   ix, jx, ua = USED(a), ub = USED(b); +  mw_mp_digit *pa, *pb, *pt, *pbt; + +  if((res = mw_mp_init_size(&tmp, ua + ub)) != MP_OKAY) +    return res; + +  /* This has the effect of left-padding with zeroes... */ +  USED(&tmp) = ua + ub; + +  /* We're going to need the base value each iteration */ +  pbt = DIGITS(&tmp); + +  /* Outer loop:  Digits of b */ + +  pb = DIGITS(b); +  for(ix = 0; ix < ub; ++ix, ++pb) { +    if(*pb == 0)  +      continue; + +    /* Inner product:  Digits of a */ +    pa = DIGITS(a); +    for(jx = 0; jx < ua; ++jx, ++pa) { +      pt = pbt + ix + jx; +      w = *pb * *pa + k + *pt; +      *pt = ACCUM(w); +      k = CARRYOUT(w); +    } + +    pbt[ix + jx] = k; +    k = 0; +  } + +  s_mw_mp_clamp(&tmp); +  s_mw_mp_exch(&tmp, a); + +  mw_mp_clear(&tmp); + +  return MP_OKAY; + +} /* end s_mw_mp_mul() */ + +/* }}} */ + +/* {{{ s_mw_mp_kmul(a, b, out, len) */ + +#if 0 +void   s_mw_mp_kmul(mw_mp_digit *a, mw_mp_digit *b, mw_mp_digit *out, mw_mp_size len) +{ +  mw_mp_word   w, k = 0; +  mw_mp_size   ix, jx; +  mw_mp_digit *pa, *pt; + +  for(ix = 0; ix < len; ++ix, ++b) { +    if(*b == 0) +      continue; +     +    pa = a; +    for(jx = 0; jx < len; ++jx, ++pa) { +      pt = out + ix + jx; +      w = *b * *pa + k + *pt; +      *pt = ACCUM(w); +      k = CARRYOUT(w); +    } + +    out[ix + jx] = k; +    k = 0; +  } + +} /* end s_mw_mp_kmul() */ +#endif + +/* }}} */ + +/* {{{ s_mw_mp_sqr(a) */ + +/* +  Computes the square of a, in place.  This can be done more +  efficiently than a general multiplication, because many of the +  computation steps are redundant when squaring.  The inner product +  step is a bit more complicated, but we save a fair number of +  iterations of the multiplication loop. + */ +#if MP_SQUARE +mw_mp_err   s_mw_mp_sqr(mw_mp_int *a) +{ +  mw_mp_word  w, k = 0; +  mw_mp_int   tmp; +  mw_mp_err   res; +  mw_mp_size  ix, jx, kx, used = USED(a); +  mw_mp_digit *pa1, *pa2, *pt, *pbt; + +  if((res = mw_mp_init_size(&tmp, 2 * used)) != MP_OKAY) +    return res; + +  /* Left-pad with zeroes */ +  USED(&tmp) = 2 * used; + +  /* We need the base value each time through the loop */ +  pbt = DIGITS(&tmp); + +  pa1 = DIGITS(a); +  for(ix = 0; ix < used; ++ix, ++pa1) { +    if(*pa1 == 0) +      continue; + +    w = DIGIT(&tmp, ix + ix) + (*pa1 * *pa1); + +    pbt[ix + ix] = ACCUM(w); +    k = CARRYOUT(w); + +    /* +      The inner product is computed as: + +         (C, S) = t[i,j] + 2 a[i] a[j] + C + +      This can overflow what can be represented in an mw_mp_word, and +      since C arithmetic does not provide any way to check for +      overflow, we have to check explicitly for overflow conditions +      before they happen. +     */ +    for(jx = ix + 1, pa2 = DIGITS(a) + jx; jx < used; ++jx, ++pa2) { +      mw_mp_word  u = 0, v; +       +      /* Store this in a temporary to avoid indirections later */ +      pt = pbt + ix + jx; + +      /* Compute the multiplicative step */ +      w = *pa1 * *pa2; + +      /* If w is more than half MP_WORD_MAX, the doubling will +	 overflow, and we need to record a carry out into the next +	 word */ +      u = (w >> (MP_WORD_BIT - 1)) & 1; + +      /* Double what we've got, overflow will be ignored as defined +	 for C arithmetic (we've already noted if it is to occur) +       */ +      w *= 2; + +      /* Compute the additive step */ +      v = *pt + k; + +      /* If we do not already have an overflow carry, check to see +	 if the addition will cause one, and set the carry out if so  +       */ +      u |= ((MP_WORD_MAX - v) < w); + +      /* Add in the rest, again ignoring overflow */ +      w += v; + +      /* Set the i,j digit of the output */ +      *pt = ACCUM(w); + +      /* Save carry information for the next iteration of the loop. +	 This is why k must be an mw_mp_word, instead of an mw_mp_digit */ +      k = CARRYOUT(w) | (u << DIGIT_BIT); + +    } /* for(jx ...) */ + +    /* Set the last digit in the cycle and reset the carry */ +    k = DIGIT(&tmp, ix + jx) + k; +    pbt[ix + jx] = ACCUM(k); +    k = CARRYOUT(k); + +    /* If we are carrying out, propagate the carry to the next digit +       in the output.  This may cascade, so we have to be somewhat +       circumspect -- but we will have enough precision in the output +       that we won't overflow  +     */ +    kx = 1; +    while(k) { +      k = pbt[ix + jx + kx] + 1; +      pbt[ix + jx + kx] = ACCUM(k); +      k = CARRYOUT(k); +      ++kx; +    } +  } /* for(ix ...) */ + +  s_mw_mp_clamp(&tmp); +  s_mw_mp_exch(&tmp, a); + +  mw_mp_clear(&tmp); + +  return MP_OKAY; + +} /* end s_mw_mp_sqr() */ +#endif + +/* }}} */ + +/* {{{ s_mw_mp_div(a, b) */ + +/* +  s_mw_mp_div(a, b) + +  Compute a = a / b and b = a mod b.  Assumes b > a. + */ + +mw_mp_err   s_mw_mp_div(mw_mp_int *a, mw_mp_int *b) +{ +  mw_mp_int   quot, rem, t; +  mw_mp_word  q; +  mw_mp_err   res; +  mw_mp_digit d; +  int      ix; + +  if(mw_mp_cmw_mp_z(b) == 0) +    return MP_RANGE; + +  /* Shortcut if b is power of two */ +  if((ix = s_mw_mp_ispow2(b)) >= 0) { +    mw_mp_copy(a, b);  /* need this for remainder */ +    s_mw_mp_div_2d(a, (mw_mp_digit)ix); +    s_mw_mp_mod_2d(b, (mw_mp_digit)ix); + +    return MP_OKAY; +  } + +  /* Allocate space to store the quotient */ +  if((res = mw_mp_init_size(", USED(a))) != MP_OKAY) +    return res; + +  /* A working temporary for division     */ +  if((res = mw_mp_init_size(&t, USED(a))) != MP_OKAY) +    goto T; + +  /* Allocate space for the remainder     */ +  if((res = mw_mp_init_size(&rem, USED(a))) != MP_OKAY) +    goto REM; + +  /* Normalize to optimize guessing       */ +  d = s_mw_mp_norm(a, b); + +  /* Perform the division itself...woo!   */ +  ix = USED(a) - 1; + +  while(ix >= 0) { +    /* Find a partial substring of a which is at least b */ +    while(s_mw_mp_cmp(&rem, b) < 0 && ix >= 0) { +      if((res = s_mw_mp_lshd(&rem, 1)) != MP_OKAY)  +	goto CLEANUP; + +      if((res = s_mw_mp_lshd(", 1)) != MP_OKAY) +	goto CLEANUP; + +      DIGIT(&rem, 0) = DIGIT(a, ix); +      s_mw_mp_clamp(&rem); +      --ix; +    } + +    /* If we didn't find one, we're finished dividing    */ +    if(s_mw_mp_cmp(&rem, b) < 0)  +      break;     + +    /* Compute a guess for the next quotient digit       */ +    q = DIGIT(&rem, USED(&rem) - 1); +    if(q <= DIGIT(b, USED(b) - 1) && USED(&rem) > 1) +      q = (q << DIGIT_BIT) | DIGIT(&rem, USED(&rem) - 2); + +    q /= DIGIT(b, USED(b) - 1); + +    /* The guess can be as much as RADIX + 1 */ +    if(q >= RADIX) +      q = RADIX - 1; + +    /* See what that multiplies out to                   */ +    mw_mp_copy(b, &t); +    if((res = s_mw_mp_mul_d(&t, q)) != MP_OKAY) +      goto CLEANUP; + +    /*  +       If it's too big, back it off.  We should not have to do this +       more than once, or, in rare cases, twice.  Knuth describes a +       method by which this could be reduced to a maximum of once, but +       I didn't implement that here. +     */ +    while(s_mw_mp_cmp(&t, &rem) > 0) { +      --q; +      s_mw_mp_sub(&t, b); +    } + +    /* At this point, q should be the right next digit   */ +    if((res = s_mw_mp_sub(&rem, &t)) != MP_OKAY) +      goto CLEANUP; + +    /* +      Include the digit in the quotient.  We allocated enough memory +      for any quotient we could ever possibly get, so we should not +      have to check for failures here +     */ +    DIGIT(", 0) = q; +  } + +  /* Denormalize remainder                */ +  if(d != 0)  +    s_mw_mp_div_2d(&rem, d); + +  s_mw_mp_clamp("); +  s_mw_mp_clamp(&rem); + +  /* Copy quotient back to output         */ +  s_mw_mp_exch(", a); +   +  /* Copy remainder back to output        */ +  s_mw_mp_exch(&rem, b); + +CLEANUP: +  mw_mp_clear(&rem); +REM: +  mw_mp_clear(&t); +T: +  mw_mp_clear("); + +  return res; + +} /* end s_mw_mp_div() */ + +/* }}} */ + +/* {{{ s_mw_mp_2expt(a, k) */ + +mw_mp_err   s_mw_mp_2expt(mw_mp_int *a, mw_mp_digit k) +{ +  mw_mp_err    res; +  mw_mp_size   dig, bit; + +  dig = k / DIGIT_BIT; +  bit = k % DIGIT_BIT; + +  mw_mp_zero(a); +  if((res = s_mw_mp_pad(a, dig + 1)) != MP_OKAY) +    return res; +   +  DIGIT(a, dig) |= (1 << bit); + +  return MP_OKAY; + +} /* end s_mw_mp_2expt() */ + +/* }}} */ + +/* {{{ s_mw_mp_reduce(x, m, mu) */ + +/* +  Compute Barrett reduction, x (mod m), given a precomputed value for +  mu = b^2k / m, where b = RADIX and k = #digits(m).  This should be +  faster than straight division, when many reductions by the same +  value of m are required (such as in modular exponentiation).  This +  can nearly halve the time required to do modular exponentiation, +  as compared to using the full integer divide to reduce. + +  This algorithm was derived from the _Handbook of Applied +  Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14, +  pp. 603-604.   + */ + +mw_mp_err   s_mw_mp_reduce(mw_mp_int *x, mw_mp_int *m, mw_mp_int *mu) +{ +  mw_mp_int   q; +  mw_mp_err   res; +  mw_mp_size  um = USED(m); + +  if((res = mw_mp_init_copy(&q, x)) != MP_OKAY) +    return res; + +  s_mw_mp_rshd(&q, um - 1);       /* q1 = x / b^(k-1)  */ +  s_mw_mp_mul(&q, mu);            /* q2 = q1 * mu      */ +  s_mw_mp_rshd(&q, um + 1);       /* q3 = q2 / b^(k+1) */ + +  /* x = x mod b^(k+1), quick (no division) */ +  s_mw_mp_mod_2d(x, DIGIT_BIT * (um + 1)); + +  /* q = q * m mod b^(k+1), quick (no division) */ +  s_mw_mp_mul(&q, m); +  s_mw_mp_mod_2d(&q, DIGIT_BIT * (um + 1)); + +  /* x = x - q */ +  if((res = mw_mp_sub(x, &q, x)) != MP_OKAY) +    goto CLEANUP; + +  /* If x < 0, add b^(k+1) to it */ +  if(mw_mp_cmw_mp_z(x) < 0) { +    mw_mp_set(&q, 1); +    if((res = s_mw_mp_lshd(&q, um + 1)) != MP_OKAY) +      goto CLEANUP; +    if((res = mw_mp_add(x, &q, x)) != MP_OKAY) +      goto CLEANUP; +  } + +  /* Back off if it's too big */ +  while(mw_mp_cmp(x, m) >= 0) { +    if((res = s_mw_mp_sub(x, m)) != MP_OKAY) +      break; +  } + + CLEANUP: +  mw_mp_clear(&q); + +  return res; + +} /* end s_mw_mp_reduce() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive comparisons */ + +/* {{{ s_mw_mp_cmp(a, b) */ + +/* Compare |a| <=> |b|, return 0 if equal, <0 if a<b, >0 if a>b           */ +int      s_mw_mp_cmp(mw_mp_int *a, mw_mp_int *b) +{ +  mw_mp_size   ua = USED(a), ub = USED(b); + +  if(ua > ub) +    return MP_GT; +  else if(ua < ub) +    return MP_LT; +  else { +    int      ix = ua - 1; +    mw_mp_digit *ap = DIGITS(a) + ix, *bp = DIGITS(b) + ix; + +    while(ix >= 0) { +      if(*ap > *bp) +	return MP_GT; +      else if(*ap < *bp) +	return MP_LT; + +      --ap; --bp; --ix; +    } + +    return MP_EQ; +  } + +} /* end s_mw_mp_cmp() */ + +/* }}} */ + +/* {{{ s_mw_mp_cmw_mp_d(a, d) */ + +/* Compare |a| <=> d, return 0 if equal, <0 if a<d, >0 if a>d             */ +int      s_mw_mp_cmw_mp_d(mw_mp_int *a, mw_mp_digit d) +{ +  mw_mp_size  ua = USED(a); +  mw_mp_digit *ap = DIGITS(a); + +  if(ua > 1) +    return MP_GT; + +  if(*ap < d)  +    return MP_LT; +  else if(*ap > d) +    return MP_GT; +  else +    return MP_EQ; + +} /* end s_mw_mp_cmw_mp_d() */ + +/* }}} */ + +/* {{{ s_mw_mp_ispow2(v) */ + +/* +  Returns -1 if the value is not a power of two; otherwise, it returns +  k such that v = 2^k, i.e. lg(v). + */ +int      s_mw_mp_ispow2(mw_mp_int *v) +{ +  mw_mp_digit d, *dp; +  mw_mp_size  uv = USED(v); +  int      extra = 0, ix; + +  d = DIGIT(v, uv - 1); /* most significant digit of v */ + +  while(d && ((d & 1) == 0)) { +    d >>= 1; +    ++extra; +  } + +  if(d == 1) { +    ix = uv - 2; +    dp = DIGITS(v) + ix; + +    while(ix >= 0) { +      if(*dp) +	return -1; /* not a power of two */ + +      --dp; --ix; +    } + +    return ((uv - 1) * DIGIT_BIT) + extra; +  }  + +  return -1; + +} /* end s_mw_mp_ispow2() */ + +/* }}} */ + +/* {{{ s_mw_mp_ispow2d(d) */ + +int      s_mw_mp_ispow2d(mw_mp_digit d) +{ +  int   pow = 0; + +  while((d & 1) == 0) { +    ++pow; d >>= 1; +  } + +  if(d == 1) +    return pow; + +  return -1; + +} /* end s_mw_mp_ispow2d() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive I/O helpers */ + +/* {{{ s_mw_mp_tovalue(ch, r) */ + +/* +  Convert the given character to its digit value, in the given radix. +  If the given character is not understood in the given radix, -1 is +  returned.  Otherwise the digit's numeric value is returned. + +  The results will be odd if you use a radix < 2 or > 62, you are +  expected to know what you're up to. + */ +int      s_mw_mp_tovalue(char ch, int r) +{ +  int    val, xch; +   +  if(r > 36) +    xch = ch; +  else +    xch = toupper(ch); + +  if(isdigit(xch)) +    val = xch - '0'; +  else if(isupper(xch)) +    val = xch - 'A' + 10; +  else if(islower(xch)) +    val = xch - 'a' + 36; +  else if(xch == '+') +    val = 62; +  else if(xch == '/') +    val = 63; +  else  +    return -1; + +  if(val < 0 || val >= r) +    return -1; + +  return val; + +} /* end s_mw_mp_tovalue() */ + +/* }}} */ + +/* {{{ s_mw_mp_todigit(val, r, low) */ + +/* +  Convert val to a radix-r digit, if possible.  If val is out of range +  for r, returns zero.  Otherwise, returns an ASCII character denoting +  the value in the given radix. + +  The results may be odd if you use a radix < 2 or > 64, you are +  expected to know what you're doing. + */ +   +char     s_mw_mp_todigit(int val, int r, int low) +{ +  char   ch; + +  if(val < 0 || val >= r) +    return 0; + +  ch = s_dmap_1[val]; + +  if(r <= 36 && low) +    ch = tolower(ch); + +  return ch; + +} /* end s_mw_mp_todigit() */ + +/* }}} */ + +/* {{{ s_mw_mp_outlen(bits, radix) */ + +/*  +   Return an estimate for how long a string is needed to hold a radix +   r representation of a number with 'bits' significant bits. + +   Does not include space for a sign or a NUL terminator. + */ +int      s_mw_mp_outlen(int bits, int r) +{ +  return (int)((double)bits * LOG_V_2(r) + 0.5); + +} /* end s_mw_mp_outlen() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* HERE THERE BE DRAGONS                                                  */ diff --git a/protocols/Sametime/src/meanwhile/src/mpi/mpi.h b/protocols/Sametime/src/meanwhile/src/mpi/mpi.h new file mode 100644 index 0000000000..0e7cc527a1 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mpi/mpi.h @@ -0,0 +1,221 @@ +/* +  mpi.h +   +  by Michael J. Fromberger <http://www.dartmouth.edu/~sting/> +  Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved +   +  Arbitrary precision integer arithmetic library +   +  modified for use in Meanwhile as a convenience library +*/ + +#ifndef _H_MPI_ +#define _H_MPI_ + +#include "mpi-config.h" + +#if MP_DEBUG +#undef MP_IOFUNC +#define MP_IOFUNC 1 +#endif + +#if MP_IOFUNC +#include <stdio.h> +#include <ctype.h> +#endif + +#include <limits.h> + +#define  MP_NEG  1 +#define  MP_ZPOS 0 + +/* Included for compatibility... */ +#define  NEG     MP_NEG +#define  ZPOS    MP_ZPOS + +#define  MP_OKAY          0 /* no error, all is well */ +#define  MP_YES           0 /* yes (boolean result)  */ +#define  MP_NO           -1 /* no (boolean result)   */ +#define  MP_MEM          -2 /* out of memory         */ +#define  MP_RANGE        -3 /* argument out of range */ +#define  MP_BADARG       -4 /* invalid parameter     */ +#define  MP_UNDEF        -5 /* answer is undefined   */ +#define  MP_LAST_CODE    MP_UNDEF + +#include "mpi-types.h" + +/* Included for compatibility... */ +#define DIGIT_BIT         MP_DIGIT_BIT +#define DIGIT_MAX         MP_DIGIT_MAX + +/* Macros for accessing the mw_mp_int internals           */ +#define  SIGN(MP)     ((MP)->sign) +#define  USED(MP)     ((MP)->used) +#define  ALLOC(MP)    ((MP)->alloc) +#define  DIGITS(MP)   ((MP)->dp) +#define  DIGIT(MP,N)  (MP)->dp[(N)] + +#if MP_ARGCHK == 1 +#define  ARGCHK(X,Y)  {if(!(X)){return (Y);}} +#elif MP_ARGCHK == 2 +#include <assert.h> +#define  ARGCHK(X,Y)  assert(X) +#else +#define  ARGCHK(X,Y)  /*  */ +#endif + +/* This defines the maximum I/O base (minimum is 2)   */ +#define MAX_RADIX         64 + +typedef struct { +  mw_mp_sign       sign;    /* sign of this quantity      */ +  mw_mp_size       alloc;   /* how many digits allocated  */ +  mw_mp_size       used;    /* how many digits used       */ +  mw_mp_digit     *dp;      /* the digits themselves      */ +} mw_mp_int; + +/*------------------------------------------------------------------------*/ +/* Default precision                                                      */ + +unsigned int mw_mp_get_prec(void); +void         mw_mp_set_prec(unsigned int prec); + +/*------------------------------------------------------------------------*/ +/* Memory management                                                      */ + +mw_mp_err mw_mp_init(mw_mp_int *mp); +mw_mp_err mw_mp_init_array(mw_mp_int mp[], int count); +mw_mp_err mw_mp_init_size(mw_mp_int *mp, mw_mp_size prec); +mw_mp_err mw_mp_init_copy(mw_mp_int *mp, mw_mp_int *from); +mw_mp_err mw_mp_copy(mw_mp_int *from, mw_mp_int *to); +void   mw_mp_exch(mw_mp_int *mp1, mw_mp_int *mp2); +void   mw_mp_clear(mw_mp_int *mp); +void   mw_mp_clear_array(mw_mp_int mp[], int count); +void   mw_mp_zero(mw_mp_int *mp); +void   mw_mp_set(mw_mp_int *mp, mw_mp_digit d); +mw_mp_err mw_mp_set_int(mw_mp_int *mp, long z); + +/*------------------------------------------------------------------------*/ +/* Single digit arithmetic                                                */ + +mw_mp_err mw_mp_add_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b); +mw_mp_err mw_mp_sub_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b); +mw_mp_err mw_mp_mul_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *b); +mw_mp_err mw_mp_mul_2(mw_mp_int *a, mw_mp_int *c); +mw_mp_err mw_mp_div_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *q, mw_mp_digit *r); +mw_mp_err mw_mp_div_2(mw_mp_int *a, mw_mp_int *c); +mw_mp_err mw_mp_expt_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *c); + +/*------------------------------------------------------------------------*/ +/* Sign manipulations                                                     */ + +mw_mp_err mw_mp_abs(mw_mp_int *a, mw_mp_int *b); +mw_mp_err mw_mp_neg(mw_mp_int *a, mw_mp_int *b); + +/*------------------------------------------------------------------------*/ +/* Full arithmetic                                                        */ + +mw_mp_err mw_mp_add(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c); +mw_mp_err mw_mp_sub(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c); +mw_mp_err mw_mp_mul(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c); +mw_mp_err mw_mp_mul_2d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *c); +#if MP_SQUARE +mw_mp_err mw_mp_sqr(mw_mp_int *a, mw_mp_int *b); +#else +#define mw_mp_sqr(a, b) mw_mp_mul(a, a, b) +#endif +mw_mp_err mw_mp_div(mw_mp_int *a, mw_mp_int *b, mw_mp_int *q, mw_mp_int *r); +mw_mp_err mw_mp_div_2d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *q, mw_mp_int *r); +mw_mp_err mw_mp_expt(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c); +mw_mp_err mw_mp_2expt(mw_mp_int *a, mw_mp_digit k); +mw_mp_err mw_mp_sqrt(mw_mp_int *a, mw_mp_int *b); + +/*------------------------------------------------------------------------*/ +/* Modular arithmetic                                                     */ + +#if MP_MODARITH +mw_mp_err mw_mp_mod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c); +mw_mp_err mw_mp_mod_d(mw_mp_int *a, mw_mp_digit d, mw_mp_digit *c); +mw_mp_err mw_mp_addmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c); +mw_mp_err mw_mp_submod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c); +mw_mp_err mw_mp_mulmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c); +#if MP_SQUARE +mw_mp_err mw_mp_sqrmod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c); +#else +#define mw_mp_sqrmod(a, m, c) mw_mp_mulmod(a, a, m, c) +#endif +mw_mp_err mw_mp_exptmod(mw_mp_int *a, mw_mp_int *b, mw_mp_int *m, mw_mp_int *c); +mw_mp_err mw_mp_exptmod_d(mw_mp_int *a, mw_mp_digit d, mw_mp_int *m, mw_mp_int *c); +#endif /* MP_MODARITH */ + +/*------------------------------------------------------------------------*/ +/* Comparisons                                                            */ + +int    mw_mp_cmw_mp_z(mw_mp_int *a); +int    mw_mp_cmw_mp_d(mw_mp_int *a, mw_mp_digit d); +int    mw_mp_cmp(mw_mp_int *a, mw_mp_int *b); +int    mw_mp_cmw_mp_mag(mw_mp_int *a, mw_mp_int *b); +int    mw_mp_cmw_mp_int(mw_mp_int *a, long z); +int    mw_mp_isodd(mw_mp_int *a); +int    mw_mp_iseven(mw_mp_int *a); + +/*------------------------------------------------------------------------*/ +/* Number theoretic                                                       */ + +#if MP_NUMTH +mw_mp_err mw_mp_gcd(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c); +mw_mp_err mw_mp_lcm(mw_mp_int *a, mw_mp_int *b, mw_mp_int *c); +mw_mp_err mw_mp_xgcd(mw_mp_int *a, mw_mp_int *b, mw_mp_int *g, mw_mp_int *x, mw_mp_int *y); +mw_mp_err mw_mp_invmod(mw_mp_int *a, mw_mp_int *m, mw_mp_int *c); +#endif /* end MP_NUMTH */ + +/*------------------------------------------------------------------------*/ +/* Input and output                                                       */ + +#if MP_IOFUNC +void   mw_mp_print(mw_mp_int *mp, FILE *ofp); +#endif /* end MP_IOFUNC */ + +/*------------------------------------------------------------------------*/ +/* Base conversion                                                        */ + +#define BITS     1 +#define BYTES    CHAR_BIT + +mw_mp_err mw_mp_read_signed_bin(mw_mp_int *mp, unsigned char *str, int len); +int    mw_mp_signed_bin_size(mw_mp_int *mp); +mw_mp_err mw_mp_to_signed_bin(mw_mp_int *mp, unsigned char *str); + +mw_mp_err mw_mp_read_unsigned_bin(mw_mp_int *mp, unsigned char *str, int len); +int    mw_mp_unsigned_bin_size(mw_mp_int *mp); +mw_mp_err mw_mp_to_unsigned_bin(mw_mp_int *mp, unsigned char *str); + +int    mw_mp_count_bits(mw_mp_int *mp); + +#if MP_COMPAT_MACROS +#define mw_mp_read_raw(mp, str, len) mw_mp_read_signed_bin((mp), (str), (len)) +#define mw_mp_raw_size(mp)           mw_mp_signed_bin_size(mp) +#define mw_mp_toraw(mp, str)         mw_mp_to_signed_bin((mp), (str)) +#define mw_mp_read_mag(mp, str, len) mw_mp_read_unsigned_bin((mp), (str), (len)) +#define mw_mp_mag_size(mp)           mw_mp_unsigned_bin_size(mp) +#define mw_mp_tomag(mp, str)         mw_mp_to_unsigned_bin((mp), (str)) +#endif + +mw_mp_err mw_mp_read_radix(mw_mp_int *mp, unsigned char *str, int radix); +int    mw_mp_radix_size(mw_mp_int *mp, int radix); +int    mw_mp_value_radix_size(int num, int qty, int radix); +mw_mp_err mw_mp_toradix(mw_mp_int *mp, unsigned char *str, int radix); + +int    mw_mp_char2value(char ch, int r); + +#define mw_mp_tobinary(M, S)  mw_mp_toradix((M), (S), 2) +#define mw_mp_tooctal(M, S)   mw_mp_toradix((M), (S), 8) +#define mw_mp_todecimal(M, S) mw_mp_toradix((M), (S), 10) +#define mw_mp_tohex(M, S)     mw_mp_toradix((M), (S), 16) + +/*------------------------------------------------------------------------*/ +/* Error strings                                                          */ + +const  char  *mw_mp_strerror(mw_mp_err ec); + +#endif /* end _H_MPI_ */ diff --git a/protocols/Sametime/src/meanwhile/src/mw_channel.h b/protocols/Sametime/src/meanwhile/src/mw_channel.h new file mode 100644 index 0000000000..7af5e22d86 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_channel.h @@ -0,0 +1,380 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_CHANNEL_H +#define _MW_CHANNEL_H + + +/** @file mw_channel.h +     +Life-cycle of an outgoing channel: + +1: mwChannel_new is called. If there is a channel in the outgoing +collection in state NEW, then it is returned. Otherwise, a channel +is allocated, assigned a unique outgoing id, marked as NEW, and +returned. + +2: channel is set to INIT status (effectively earmarking it as in- +use).  fields on the channel can then be set as necessary to +prepare it for creation. + +3: mwChannel_create is called. The channel is marked to WAIT status +and a message is sent to the server. The channel is also marked as +inactive as of that moment. + +4: the channel is accepted (step 5) or rejected (step 7) + +5: an accept message is received from the server, and the channel +is marked as OPEN, and the inactive mark is removed. And messages +in the in or out queues for that channel are processed. The channel +is now ready to be used. + +6: data is sent and received over the channel + +7: the channel is closed either by receipt of a close message or by +local action. If by local action, then a close message is sent to +the server.  The channel is cleaned up, its queues dumped, and it +is set to NEW status to await re-use. + +Life-cycle of an incoming channel: + +1: a channel create message is received. A channel is allocated and +given an id matching the message. It is placed in status WAIT, and +marked as inactive as of that moment. The service matching that +channel is alerted of the incoming creation request. + +2: the service can either accept (step 3) or reject (step 5) the +channel + +3: mwChannel_accept is called. The channel is marked as OPEN, and +an accept message is sent to the server. And messages in the in or +out queues for that channel are processed. The channel is now ready +to be used. + +4: data is sent and received over the channel + +5: The channel is closed either by receipt of a close message or by +local action. If by local action, then a close message is sent to +the server.  The channel is cleaned up, its queues dumped, and it +is deallocated. */ + + +#include <time.h> +#include "mw_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* place-holders */ +struct mwCipherInstance; +struct mwMsgChannelAccept; +struct mwMsgChannelCreate; +struct mwMsgChannelDestroy; +struct mwMsgChannelSend; +struct mwService; +struct mwSession; + + + +/** @struct mwChannel +    Represents a channel to a service */ +struct mwChannel; + + +/** @struct mwChannelSet +    Collection of channels */ +struct mwChannelSet; + + +/** special ID indicating the master channel */ +#define MW_MASTER_CHANNEL_ID  0x00000000 + + +/** non-zero if a channel id appears to be that of an outgoing channel */ +#define mwChannel_idIsOutgoing(id) \ +  (! (0x80000000 & (id))) + +/** non-zero if a channel id appears to be that of an incoming channel */ +#define mwChannel_idIsIncoming(id) \ +  (! mwChannel_idIsOutgoing(id)) + +/** non-zero if a channel appears to be an outgoing channel */ +#define mwChannel_isOutgoing(chan) \ +  mwChannel_idIsOutgoing(mwChannel_getId(chan)) + +/** non-zero if a channel appears to be an incoming channel */ +#define mwChannel_isIncoming(chan) \ +  mwChannel_idIsIncoming(mwChannel_getId(chan)) + + +/** channel status */ +enum mwChannelState { +  mwChannel_NEW,      /**< channel is newly allocated, in the pool */ +  mwChannel_INIT,     /**< channel is being prepared, out of the pool */ +  mwChannel_WAIT,     /**< channel is waiting for accept */ +  mwChannel_OPEN,     /**< channel is accepted and open */ +  mwChannel_DESTROY,  /**< channel is being destroyed */ +  mwChannel_ERROR,    /**< channel is being destroyed due to error */ +  mwChannel_UNKNOWN,  /**< unknown state, or error determining state */ +}; + + +#define mwChannel_isState(chan, state) \ +  (mwChannel_getState(chan) == (state)) + + +/** channel statistic fields. +    @see mwChannel_getStatistic */ +enum mwChannelStatField { +  mwChannelStat_MSG_SENT,      /**< total send-on-chan messages sent */ +  mwChannelStat_MSG_RECV,      /**< total send-on-chan messages received */ +  mwChannelStat_U_BYTES_SENT,  /**< total bytes sent, pre-encryption */ +  mwChannelStat_U_BYTES_RECV,  /**< total bytes received, post-decryption */ +  mwChannelStat_OPENED_AT,     /**< time when channel was opened */ +  mwChannelStat_CLOSED_AT,     /**< time when channel was closed */ +}; + + +/** @enum mwEncryptPolicy + +    Policy for a channel, dictating what sort of encryption should be +    used, if any, and when. +*/ +enum mwEncryptPolicy { +  mwEncrypt_NONE      = 0x0000, /**< encrypt none */ +  mwEncrypt_WHATEVER  = 0x0001, /**< encrypt whatever you want */ +  mwEncrypt_ALL       = 0x0002, /**< encrypt all, any cipher */ +  mwEncrypt_RC2_40    = 0x1000, /**< encrypt all, RC2/40 cipher */ +  mwEncrypt_RC2_128   = 0x2000, /**< encrypt all, RC2/128 cipher */ +}; + + +/** Allocate and initialize a channel set for a session */ +struct mwChannelSet *mwChannelSet_new(struct mwSession *); + + +/** Clear and deallocate a channel set. Closes, clears, and frees all +    contained channels. */ +void mwChannelSet_free(struct mwChannelSet *); + + +/** Create an incoming channel with the given channel id. Channel's state +    will be set to WAIT. Primarily for use in mw_session */ +struct mwChannel *mwChannel_newIncoming(struct mwChannelSet *, guint32 id); + + +/** Create an outgoing channel. Its channel ID will be generated by +    the owning channel set. Channel's state will be set to INIT */ +struct mwChannel *mwChannel_newOutgoing(struct mwChannelSet *); + + +/** Obtain a reference to a channel by its id. +    @returns the channel matching chan, or NULL */ +struct mwChannel *mwChannel_find(struct mwChannelSet *cs, guint32 chan); + + +/** get the ID for a channel. 0x00 indicates an error, as that is not +    a permissible value */ +guint32 mwChannel_getId(struct mwChannel *); + + +/** get the session for a channel. */ +struct mwSession *mwChannel_getSession(struct mwChannel *); + + +/** get the ID of the service for a channel. This may be 0x00 for NEW +    channels */ +guint32 mwChannel_getServiceId(struct mwChannel *); + + +/** get the service for a channel. This may be NULL for NEW +    channels */ +struct mwService *mwChannel_getService(struct mwChannel *); + + +/** associate a channel with an owning service */ +void mwChannel_setService(struct mwChannel *chan, struct mwService *srvc); + + +/** get service-specific data. This is for use by service +    implementations to easily associate information with the +    channel */ +gpointer mwChannel_getServiceData(struct mwChannel *chan); + + +/** set service-specific data. This is for use by service +    implementations to easily associate information with the +    channel */ +void mwChannel_setServiceData(struct mwChannel *chan, +			      gpointer data, GDestroyNotify clean); + + +void mwChannel_removeServiceData(struct mwChannel *chan); + + +guint32 mwChannel_getProtoType(struct mwChannel *chan); + + +void mwChannel_setProtoType(struct mwChannel *chan, guint32 proto_type); + + +guint32 mwChannel_getProtoVer(struct mwChannel *chan); + + +void mwChannel_setProtoVer(struct mwChannel *chan, guint32 proto_ver); + + +/** Channel encryption policy. + +    Cannot currently be set, used internally to automatically +    negotiate ciphers. Future revisions may allow this to be specified +    in a new channel to dictate channel encryption. + +    @see enum mwEncryptPolicy +*/ +guint16 mwChannel_getEncryptPolicy(struct mwChannel *chan); + + +guint32 mwChannel_getOptions(struct mwChannel *chan); + + +void mwChannel_setOptions(struct mwChannel *chan, guint32 options); + + +/** User at the other end of the channel. The target user for outgoing +    channels, the creator for incoming channels */ +struct mwLoginInfo *mwChannel_getUser(struct mwChannel *chan); + + +/** direct reference to the create addtl information for a channel */ +struct mwOpaque *mwChannel_getAddtlCreate(struct mwChannel *); + + +/** direct reference to the accept addtl information for a channel */ +struct mwOpaque *mwChannel_getAddtlAccept(struct mwChannel *); + + +/** automatically adds instances of all ciphers in the session to the +    list of supported ciphers for a channel */ +void mwChannel_populateSupportedCipherInstances(struct mwChannel *chan); + + +/** add a cipher instance to a channel's list of supported +    ciphers. Channel must be NEW. */ +void mwChannel_addSupportedCipherInstance(struct mwChannel *chan, +					  struct mwCipherInstance *ci); + + +/** the list of supported ciphers for a channel. This list will be +    empty once a cipher has been selected for the channel */ +GList *mwChannel_getSupportedCipherInstances(struct mwChannel *chan); + + +/** select a cipher instance for a channel. A NULL instance indicates +    that no encryption should be used. */ +void mwChannel_selectCipherInstance(struct mwChannel *chan, +				    struct mwCipherInstance *ci); + + +struct mwCipherInstance * +mwChannel_getCipherInstance(struct mwChannel *chan); + + +/** get the state of a channel  */ +enum mwChannelState mwChannel_getState(struct mwChannel *); + + +/** obtain the value for a statistic field as a gpointer */ +gpointer mwChannel_getStatistic(struct mwChannel *chan, +				enum mwChannelStatField stat); + + +/** Formally open a channel. + +    For outgoing channels: instruct the session to send a channel +    create message to the server, and to mark the channel (which must +    be in INIT status) as being in WAIT status. +    +    For incoming channels: configures the channel according to options +    in the channel create message. Marks the channel as being in WAIT +    status +*/ +int mwChannel_create(struct mwChannel *chan); + + +/** Formally accept an incoming channel. Instructs the session to send +    a channel accept message to the server, and to mark the channel as +    being OPEN. */ +int mwChannel_accept(struct mwChannel *chan); + + +/** Destroy a channel. Sends a channel-destroy message to the server, +    and perform cleanup to remove the channel. + +    @param chan    the channel to destroy +    @param reason  the reason code for closing the channel +    @param data    optional additional information  +*/ +int mwChannel_destroy(struct mwChannel *chan, guint32 reason, +		      struct mwOpaque *data); + + +/** Compose a send-on-channel message, encrypt it as per the channel's +    specification, and send it */ +int mwChannel_send(struct mwChannel *chan, guint32 msg_type, +		   struct mwOpaque *msg); + + +/** Compose a send-on-channel message, and if encrypt is TRUE, encrypt +    it as per the channel's specification, and send it */ +int mwChannel_sendEncrypted(struct mwChannel *chan, +			    guint32 msg_type, struct mwOpaque *msg, +			    gboolean encrypt); + + +/** pass a create message to a channel for handling */ +void mwChannel_recvCreate(struct mwChannel *chan, +			  struct mwMsgChannelCreate *msg); + + +/** pass an accept message to a channel for handling */ +void mwChannel_recvAccept(struct mwChannel *chan, +			  struct mwMsgChannelAccept *msg); + + +/** pass a destroy message to a channel for handling */ +void mwChannel_recvDestroy(struct mwChannel *chan, +			   struct mwMsgChannelDestroy *msg); + + +/** Feed data into a channel. */ +void mwChannel_recv(struct mwChannel *chan, struct mwMsgChannelSend *msg); + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_CHANNEL_H */ + diff --git a/protocols/Sametime/src/meanwhile/src/mw_cipher.h b/protocols/Sametime/src/meanwhile/src/mw_cipher.h new file mode 100644 index 0000000000..a75781397e --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_cipher.h @@ -0,0 +1,297 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_CIPHER_H +#define _MW_CIPHER_H + + +#include <glib.h> +#include "mw_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* place-holders */ +struct mwChannel; +struct mwSession; + + +/** @enum mwCipherType +    Common cipher types */ +enum mwCipherType { +  mwCipher_RC2_40   = 0x0000, +  mwCipher_RC2_128  = 0x0001, +}; + + +struct mwCipher; +struct mwCipherInstance; + + +/** Obtain an instance of a given cipher, which can be used for the +    processing of a single channel. */ +typedef struct mwCipherInstance *(*mwCipherInstantiator) +     (struct mwCipher *cipher, struct mwChannel *chan); + + +/** Process (encrypt or decrypt, depending) the given data. The passed +    buffer may be freed in processing and be replaced with a freshly +    allocated buffer. The post-processed buffer must in turn be freed +    after use */ +typedef int (*mwCipherProcessor) +     (struct mwCipherInstance *ci, struct mwOpaque *data); + + +/** A cipher. Ciphers are primarily used to provide cipher instances +    for bi-directional encryption on channels, but some may be used +    for other activities. Expand upon this structure to create a +    custom encryption provider. +    @see mwCipherInstance */ +struct mwCipher { + +  /** service this cipher is providing for +      @see mwCipher_getSession */ +  struct mwSession *session; + +  guint16 type;               /**< @see mwCipher_getType */ +  const char *(*get_name)();  /**< @see mwCipher_getName */ +  const char *(*get_desc)();  /**< @see mwCipher_getDesc */ + +  /** Generate a new Cipher Instance for use on a channel +      @see mwCipher_newInstance */ +  mwCipherInstantiator new_instance; + +  void (*offered)(struct mwCipherInstance *ci, struct mwEncryptItem *item); +  struct mwEncryptItem *(*offer)(struct mwCipherInstance *ci); +  void (*accepted)(struct mwCipherInstance *ci, struct mwEncryptItem *item); +  struct mwEncryptItem *(*accept)(struct mwCipherInstance *ci); + +  mwCipherProcessor encrypt; /**< @see mwCipherInstance_encrypt */ +  mwCipherProcessor decrypt; /**< @see mwCipherInstance_decrypt */ + +  /** prepare this cipher for being free'd +      @see mwCipher_free */ +  void (*clear)(struct mwCipher *c); + +  /** clean up a cipher instance before being free'd +      @see mwCipherInstance_free */ +  void (*clear_instance)(struct mwCipherInstance *ci); +}; + + +/** An instance of a cipher. Expand upon this structure to contain +    necessary state data +    @see mwCipher */ +struct mwCipherInstance { + +  /** the parent cipher. +      @see mwCipherInstance_getCipher */ +  struct mwCipher *cipher; + +  /** the channel this instances processes +      @see mwCipherInstance_getChannel */ +  struct mwChannel *channel; +}; + + +struct mwCipher *mwCipher_new_RC2_40(struct mwSession *s); + + +struct mwCipher *mwCipher_new_RC2_128(struct mwSession *s); + + +struct mwSession *mwCipher_getSession(struct mwCipher *cipher); + + +guint16 mwCipher_getType(struct mwCipher *cipher); + + +const char *mwCipher_getName(struct mwCipher *cipher); + + +const char *mwCipher_getDesc(struct mwCipher *cipher); + + +struct mwCipherInstance *mwCipher_newInstance(struct mwCipher *cipher, +					      struct mwChannel *channel); + + +/** destroy a cipher */ +void mwCipher_free(struct mwCipher* cipher); + + +/** reference the parent cipher of an instance */ +struct mwCipher *mwCipherInstance_getCipher(struct mwCipherInstance *ci); + + +/** reference the channel a cipher instance is attached to */ +struct mwChannel *mwCipherInstance_getChannel(struct mwCipherInstance *ci); + + +/** Indicates a cipher has been offered to our channel */ +void mwCipherInstance_offered(struct mwCipherInstance *ci, +			      struct mwEncryptItem *item); + + +/** Offer a cipher */ +struct mwEncryptItem * +mwCipherInstance_offer(struct mwCipherInstance *ci); + + +/** Indicates an offered cipher has been accepted */ +void mwCipherInstance_accepted(struct mwCipherInstance *ci, +			       struct mwEncryptItem *item); + + +/** Accept a cipher offered to our channel */ +struct mwEncryptItem * +mwCipherInstance_accept(struct mwCipherInstance *ci); + + +/** encrypt data */ +int mwCipherInstance_encrypt(struct mwCipherInstance *ci, +			     struct mwOpaque *data); + + +/** decrypt data */ +int mwCipherInstance_decrypt(struct mwCipherInstance *ci, +			     struct mwOpaque *data); + + +/** destroy a cipher instance */ +void mwCipherInstance_free(struct mwCipherInstance *ci); + + +/** +  @section General Cipher Functions + +  These functions are reused where encryption is necessary outside of +  a channel (eg. session authentication) +*/ +/* @{ */ + + +/** generate some pseudo-random bytes +    @param keylen  count of bytes to write into key +    @param key     buffer to write keys into +*/ +void mwKeyRandom(guchar *key, gsize keylen); + + +/** Setup an Initialization Vector. IV must be at least 8 bytes */ +void mwIV_init(guchar *iv); + + +/** Expand a variable-length key into a 128-byte key (represented as +    an an array of 64 ints) */ +void mwKeyExpand(int *ekey, const guchar *key, gsize keylen); + + +/** Encrypt data using an already-expanded key */ +void mwEncryptExpanded(const int *ekey, guchar *iv, +		       struct mwOpaque *in, +		       struct mwOpaque *out); + + +/** Encrypt data using an expanded form of the given key */ +void mwEncrypt(const guchar *key, gsize keylen, guchar *iv, +	       struct mwOpaque *in, struct mwOpaque *out); + + +/** Decrypt data using an already expanded key */ +void mwDecryptExpanded(const int *ekey, guchar *iv, +		       struct mwOpaque *in, +		       struct mwOpaque *out); + + +/** Decrypt data using an expanded form of the given key */ +void mwDecrypt(const guchar *key, gsize keylen, guchar *iv, +	       struct mwOpaque *in, struct mwOpaque *out); + + +/* @} */ + + +/** +  @section Diffie-Hellman Functions + +  These functions are reused where DH Key negotiation is necessary +  outside of a channel (eg. session authentication). These are +  wrapping a full multiple-precision integer math library, but most of +  the functionality there-of is not exposed. Currently, the math is +  provided by a copy of the public domain libmpi. + +  for more information on the used MPI Library, visit +  http://www.cs.dartmouth.edu/~sting/mpi/ +*/ +/* @{ */ + + +/** @struct mwMpi */ +struct mwMpi; + + +/** prepare a new mpi value */ +struct mwMpi *mwMpi_new(); + + +/** destroy an mpi value */ +void mwMpi_free(struct mwMpi *i); + + +/** Import a value from an opaque */ +void mwMpi_import(struct mwMpi *i, struct mwOpaque *o); + + +/** Export a value into an opaque */ +void mwMpi_export(struct mwMpi *i, struct mwOpaque *o); + + +/** set a big integer to the Sametime Prime value */ +void mwMpi_setDHPrime(struct mwMpi *i); + + +/** set a big integer to the Sametime Base value */ +void mwMpi_setDHBase(struct mwMpi *i); + + +/** sets private to a randomly generated value, and calculates public +    using the Sametime Prime and Base */ +void mwMpi_randDHKeypair(struct mwMpi *private_key, struct mwMpi *public_key); + + +/** sets the shared key value based on the remote and private keys, +    using the Sametime Prime and Base */ +void mwMpi_calculateDHShared(struct mwMpi *shared_key, struct mwMpi *remote_key, +			     struct mwMpi *private_key); + + +/* @} */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_CIPHER_H */ diff --git a/protocols/Sametime/src/meanwhile/src/mw_common.h b/protocols/Sametime/src/meanwhile/src/mw_common.h new file mode 100644 index 0000000000..1294da4959 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_common.h @@ -0,0 +1,437 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_COMMON_H +#define _MW_COMMON_H + + +/** @file mw_common.h + +    Common data types and functions for handling those types. + +    Functions in this file all fit into similar naming conventions of +    <code>TYPE_ACTION</code> as per the activity they perform. The +    following actions are available: + +    <code>void TYPE_put(struct mwPutBuffer *b, TYPE *val)</code> +    - marshalls val onto the buffer b. The buffer will grow as necessary +    to fit all the data put into it. For guint16, guint32, and +    gboolean, <code>TYPE val</code> is used instead of <code>TYPE +    \*val</code>. + +    <code>void TYPE_get(struct mwGetBuffer *b, TYPE *val)</code> +    - unmarshals val from the buffer b. Failure (due to lack of +    insufficient remaining buffer) is indicated in the buffer's error +    field. A call to a _get function with a buffer in an error state +    has to effect. + +    <code>void TYPE_clear(TYPE *val)</code> +    - zeros and frees internal members of val, but does not free val +    itself. Needs to be called before free-ing any complex types which +    have been unmarshalled from a TYPE_get or populated from a +    TYPE_clone call to prevent memory leaks. + +    <code>void TYPE_clone(TYPE *to, TYPE *from)</code> +    - copies/clones members of from into to. May result in memory +    allocation for some types. Note that to is not cleared +    before-hand, it must already be in a pristine condition. + +    <code>gboolean TYPE_equal(TYPE *y, TYPE *z)</code> +    - simple equality test. +*/ + + +#include <glib.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** @struct mwPutBuffer +    buffer to be written to */ +struct mwPutBuffer; + +/** @struct mwGetBuffer +    buffer to be read from */ +struct mwGetBuffer; + + +/** A length of binary data, not null-terminated. */ +struct mwOpaque { +  gsize len;     /**< length of data. */ +  guchar *data;  /**< data, normally with no NULL termination */ +}; + + +/* 8.3.6 Login Types */ + +/** The type of login. Normally meaning the type of client code being +    used to login with. + +    If you know of any additional client identifiers, please add them +    below or submit an RFE to the meanwhile tracker. +*/ +enum mwLoginType { +  mwLogin_LIB           = 0x1000,  /**< official Lotus binary library */ +  mwLogin_JAVA_WEB      = 0x1001,  /**< official Lotus Java applet */ +  mwLogin_BINARY        = 0x1002,  /**< official Lotus binary application */ +  mwLogin_JAVA_APP      = 0x1003,  /**< official Lotus Java application */ +  mwLogin_LINKS         = 0x100a,  /**< official Sametime Links toolkit */ + +  /* now we're getting crazy */ +  mwLogin_NOTES_6_5        = 0x1200, +  mwLogin_NOTES_6_5_3      = 0x1203, +  mwLogin_NOTES_7_0_beta   = 0x1210, +  mwLogin_NOTES_7_0        = 0x1214, +  mwLogin_ICT              = 0x1300, +  mwLogin_ICT_1_7_8_2      = 0x1302, +  mwLogin_ICT_SIP          = 0x1303, +  mwLogin_NOTESBUDDY_4_14  = 0x1400,  /**< 0xff00 mask? */ +  mwLogin_NOTESBUDDY_4_15  = 0x1405, +  mwLogin_NOTESBUDDY_4_16  = 0x1406, +  mwLogin_SANITY           = 0x1600, +  mwLogin_ST_PERL          = 0x1625, +  mwLogin_PMR_ALERT        = 0x1650, +  mwLogin_TRILLIAN         = 0x16aa,  /**< http://sf.net/st-plugin/ */ +  mwLogin_TRILLIAN_IBM     = 0x16bb, +  mwLogin_MEANWHILE        = 0x1700,  /**< Meanwhile library */ +}; + + +/* 8.2 Common Structures */ +/* 8.2.1 Login Info block */ + +struct mwLoginInfo { +  char *login_id;   /**< community-unique ID of the login */ +  guint16 type;     /**< @see mwLoginType */ +  char *user_id;    /**< community-unique ID of the user */ +  char *user_name;  /**< name of user (nick name, full name, etc) */ +  char *community;  /**< community name (usually domain name) */ +  gboolean full;    /**< if FALSE, following fields non-existant */ +  char *desc;       /**< implementation defined description */ +  guint32 ip_addr;  /**< ip addr of the login */ +  char *server_id;  /**< unique ID of login's server */ +}; + + +/* 8.2.2 Private Info Block */ + +struct mwUserItem { +  gboolean full;    /**< if FALSE, don't include name */ +  char *id;         /**< user id */ +  char *community;  /**< community */ +  char *name;       /**< user name */ +}; + + +struct mwPrivacyInfo { +  gboolean deny;             /**< deny (true) or allow (false) users */ +  guint32 count;             /**< count of users */ +  struct mwUserItem *users;  /**< the users list */ +}; + + +/* 8.3.5 User Status Types */ + +enum mwStatusType { +  mwStatus_ACTIVE  = 0x0020, +  mwStatus_IDLE    = 0x0040, +  mwStatus_AWAY    = 0x0060, +  mwStatus_BUSY    = 0x0080, +}; + + +/* 8.2.3 User Status Block */ + +struct mwUserStatus { +  guint16 status;  /**< @see mwStatusType */ +  guint32 time;    /**< last status change time in seconds */ +  char *desc;      /**< status description */ +}; + + +/* 8.2.4 ID Block */ + +struct mwIdBlock { +  char *user;       /**< user id (login id or empty for some services) */ +  char *community;  /**< community id (NULL for same community) */ +}; + + +/* 8.3.8.2 Awareness Presence Types */ + +/* @todo move mwAwareType, mwAwareIdBlock and mwAwareSnapshot into the +   aware service and out of common */ + +/** type codes for mwAwareIdBlock */ +enum mwAwareType { +  mwAware_USER    = 0x0002,  /**< a single user */ +  mwAware_GROUP   = 0x0003,  /**< a group */ +  mwAware_SERVER  = 0x0008,  /**< a server */ +}; + + +/* 8.4.2 Awareness Messages */ +/* 8.4.2.1 Awareness ID Block */ + +struct mwAwareIdBlock { +  guint16 type;     /**< @see mwAwareType */ +  char *user;       /**< user id */ +  char *community;  /**< community id (NULL for same community) */ +}; + + +/* 8.4.2.4 Snapshot */ + +struct mwAwareSnapshot { +  struct mwAwareIdBlock id; +  char *group;                 /**< group this id belongs to */ +  gboolean online;             /**< is this user online? */ +  char *alt_id;                /**< alternate ID, often same as id.user */ +  struct mwUserStatus status;  /**< status of this user */ +  char *name;                  /**< Formatted version of ID */ +}; + + +/** encryption blocks */ +struct mwEncryptItem { +  guint16 id;            /**< cipher identifier */ +  struct mwOpaque info;  /**< cipher information */ +}; + + +/** @name buffer utility functions */ +/*@{*/ + + +/** allocate a new empty buffer */ +struct mwPutBuffer *mwPutBuffer_new(); + + +/** write raw data to the put buffer */ +void mwPutBuffer_write(struct mwPutBuffer *b, gpointer data, gsize len); + + +/** destroy the buffer */ +void mwPutBuffer_free(struct mwPutBuffer *b); + + +/** move the buffer's data into an opaque, destroy the buffer */ +void mwPutBuffer_finalize(struct mwOpaque *to, struct mwPutBuffer *from); + + +/** allocate a new buffer with a copy of the given data */ +struct mwGetBuffer *mwGetBuffer_new(struct mwOpaque *data); + + +/** read len bytes of raw data from the get buffer into mem. If len is +    greater than the count of bytes remaining in the buffer, the +    buffer's error flag will NOT be set. + +    @returns count of bytes successfully copied to mem */ +gsize mwGetBuffer_read(struct mwGetBuffer *b, gpointer mem, gsize len); + + +/** skip len bytes in the get buffer. If len is greater than the count +    of bytes remaining in the buffer, the buffer's error flag will NOT +    be set. + +    @returns count of bytes successfully skipped */ +gsize mwGetBuffer_advance(struct mwGetBuffer *b, gsize len); + + +/** allocate a new buffer backed by the given data. Calling +    mwGetBuffer_free will not result in the underlying data being +    freed */ +struct mwGetBuffer *mwGetBuffer_wrap(const struct mwOpaque *data); + + +/** destroy the buffer */ +void mwGetBuffer_free(struct mwGetBuffer *b); + + +/** reset the buffer to the very beginning. Also clears the buffer's +    error flag. */ +void mwGetBuffer_reset(struct mwGetBuffer *b); + + +/** count of remaining available bytes */ +gsize mwGetBuffer_remaining(struct mwGetBuffer *b); + + +/** TRUE if an error occurred while reading a basic type from this +    buffer */ +gboolean mwGetBuffer_error(struct mwGetBuffer *b); + + +/*@}*/ + + +/** @name Basic Data Types +    The basic types are combined to construct the compound types. + */ +/*@{*/ + + +void guint16_put(struct mwPutBuffer *b, guint16 val); + +void guint16_get(struct mwGetBuffer *b, guint16 *val); + +guint16 guint16_peek(struct mwGetBuffer *b); + + +void guint32_put(struct mwPutBuffer *b, guint32 val); + +void guint32_get(struct mwGetBuffer *b, guint32 *val); + +guint32 guint32_peek(struct mwGetBuffer *b); + + +void gboolean_put(struct mwPutBuffer *b, gboolean val); + +void gboolean_get(struct mwGetBuffer *b, gboolean *val); + +gboolean gboolean_peek(struct mwGetBuffer *b); + + +void mwString_put(struct mwPutBuffer *b, const char *str); + +void mwString_get(struct mwGetBuffer *b, char **str); + + +void mwOpaque_put(struct mwPutBuffer *b, const struct mwOpaque *o); + +void mwOpaque_get(struct mwGetBuffer *b, struct mwOpaque *o); + +void mwOpaque_clear(struct mwOpaque *o); + +void mwOpaque_free(struct mwOpaque *o); + +void mwOpaque_clone(struct mwOpaque *to, const struct mwOpaque *from); + + +/*@}*/ + + +/** @name Compound Data Types */ +/*@{*/ + + +void mwLoginInfo_put(struct mwPutBuffer *b, const struct mwLoginInfo *info); + +void mwLoginInfo_get(struct mwGetBuffer *b, struct mwLoginInfo *info); + +void mwLoginInfo_clear(struct mwLoginInfo *info); + +void mwLoginInfo_clone(struct mwLoginInfo *to, const struct mwLoginInfo *from); + + +void mwUserItem_put(struct mwPutBuffer *b, const struct mwUserItem *user); + +void mwUserItem_get(struct mwGetBuffer *b, struct mwUserItem *user); + +void mwUserItem_clear(struct mwUserItem *user); + +void mwUserItem_clone(struct mwUserItem *to, const struct mwUserItem *from); + + +void mwPrivacyInfo_put(struct mwPutBuffer *b, +		       const struct mwPrivacyInfo *info); + +void mwPrivacyInfo_get(struct mwGetBuffer *b, struct mwPrivacyInfo *info); + +void mwPrivacyInfo_clear(struct mwPrivacyInfo *info); + +void mwPrivacyInfo_clone(struct mwPrivacyInfo *to, +			 const struct mwPrivacyInfo *from); + + +void mwUserStatus_put(struct mwPutBuffer *b, +		      const struct mwUserStatus *stat); + +void mwUserStatus_get(struct mwGetBuffer *b, struct mwUserStatus *stat); + +void mwUserStatus_clear(struct mwUserStatus *stat); + +void mwUserStatus_clone(struct mwUserStatus *to, +			const struct mwUserStatus *from); + + +void mwIdBlock_put(struct mwPutBuffer *b, const struct mwIdBlock *id); + +void mwIdBlock_get(struct mwGetBuffer *b, struct mwIdBlock *id); + +void mwIdBlock_clear(struct mwIdBlock *id); + +void mwIdBlock_clone(struct mwIdBlock *to, +		     const struct mwIdBlock *from); + +guint mwIdBlock_hash(const struct mwIdBlock *idb); + +gboolean mwIdBlock_equal(const struct mwIdBlock *a, +			 const struct mwIdBlock *b); + + +void mwAwareIdBlock_put(struct mwPutBuffer *b, +			const struct mwAwareIdBlock *idb); + +void mwAwareIdBlock_get(struct mwGetBuffer *b, struct mwAwareIdBlock *idb); + +void mwAwareIdBlock_clear(struct mwAwareIdBlock *idb); + +void mwAwareIdBlock_clone(struct mwAwareIdBlock *to, +			  const struct mwAwareIdBlock *from); + +guint mwAwareIdBlock_hash(const struct mwAwareIdBlock *a); + +gboolean mwAwareIdBlock_equal(const struct mwAwareIdBlock *a, +			      const struct mwAwareIdBlock *b); + + +void mwAwareSnapshot_get(struct mwGetBuffer *b, +			 struct mwAwareSnapshot *idb); + +void mwAwareSnapshot_clear(struct mwAwareSnapshot *idb); + +void mwAwareSnapshot_clone(struct mwAwareSnapshot *to, +			   const struct mwAwareSnapshot *from); + + +void mwEncryptItem_put(struct mwPutBuffer *b, +		       const struct mwEncryptItem *item); + +void mwEncryptItem_get(struct mwGetBuffer *b, struct mwEncryptItem *item); + +void mwEncryptItem_clear(struct mwEncryptItem *item); + +void mwEncryptItem_free(struct mwEncryptItem *item); + + +/*@}*/ + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_COMMON_H */ diff --git a/protocols/Sametime/src/meanwhile/src/mw_debug.c b/protocols/Sametime/src/meanwhile/src/mw_debug.c new file mode 100644 index 0000000000..cf47a38e38 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_debug.c @@ -0,0 +1,184 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + + +#include <glib/gstring.h> + +#include "mw_debug.h" + + + +#define FRMT1            "%02x" +#define FRMT2            FRMT1 FRMT1 " " +#define FRMT4            FRMT2 FRMT2 +#define FRMT8            FRMT4 FRMT4 +#define FRMT16           FRMT8 FRMT8 + +#define ADVANCE(b, n, c)  {b += c; n -= c;} + + + +/** writes hex pairs of buf to str */ +static void pretty_print(GString *str, const guchar *buf, gsize len) { +  while(len >= 16) { +    /* write a complete line */ +    g_string_append_printf(str, FRMT16, +			   buf[0],  buf[1],  buf[2],  buf[3], +			   buf[4],  buf[5],  buf[6],  buf[7], +			   buf[8],  buf[9],  buf[10], buf[11], +			   buf[12], buf[13], buf[14], buf[15]); +    ADVANCE(buf, len, 16); +     +    /* append \n to each line but the last */ +    if(len) g_string_append(str, "\n"); +  } + +  /* write an incomplete line */ +  if(len >= 8) { +    g_string_append_printf(str, FRMT8, +			   buf[0], buf[1], buf[2], buf[3], +			   buf[4], buf[5], buf[6], buf[7]); +    ADVANCE(buf, len, 8); +  } +   +  if(len >= 4) { +    g_string_append_printf(str, FRMT4, +			   buf[0], buf[1], buf[2], buf[3]); +    ADVANCE(buf, len, 4); +  } + +  if(len >= 2) { +    g_string_append_printf(str, FRMT2, buf[0], buf[1]); +    ADVANCE(buf, len, 2); +  } + +  if(len >= 1) { +    g_string_append_printf(str, FRMT1, buf[0]); +    ADVANCE(buf, len, 1); +  } +} + + + +void mw_debug_datav(const guchar *buf, gsize len, +		    const char *msg, va_list args) { +  GString *str; + +  g_return_if_fail(buf != NULL || len == 0); + +  str = g_string_new(NULL); + +  if(msg) { +    char *txt = g_strdup_vprintf(msg, args); +    g_string_append_printf(str, "%s\n", txt); +    g_free(txt); +  } +  pretty_print(str, buf, len); + +  g_debug(str->str); +  g_string_free(str, TRUE); +} + + + +void mw_debug_data(const guchar *buf, gsize len, +		   const char *msg, ...) { +  va_list args; +   +  g_return_if_fail(buf != NULL || len == 0); + +  va_start(args, msg); +  mw_debug_datav(buf, len, msg, args); +  va_end(args); +} + + + +void mw_debug_opaquev(struct mwOpaque *o, const char *txt, va_list args) { +  g_return_if_fail(o != NULL); +  mw_debug_datav(o->data, o->len, txt, args); +} + + + +void mw_debug_opaque(struct mwOpaque *o, const char *txt, ...) { +  va_list args; + +  g_return_if_fail(o != NULL); + +  va_start(args, txt); +  mw_debug_opaquev(o, txt, args); +  va_end(args); +} + + +void mw_mailme_datav(const guchar *buf, gsize len, +		     const char *info, va_list args) { + +#if MW_MAILME +  GString *str; +  char *txt; + +  str = g_string_new(MW_MAILME_MESSAGE "\n" +		     "  Please send mail to: " MW_MAILME_ADDRESS "\n" +		     MW_MAILME_CUT_START "\n"); +  str = g_string_new(NULL); + +  txt = g_strdup_vprintf(info, args); +  g_string_append_printf(str, "%s\n", txt); +  g_free(txt); + +  if(buf && len) pretty_print(str, buf, len); + +  g_string_append(str, MW_MAILME_CUT_STOP); + +  g_debug(str->str); +  g_string_free(str, TRUE); + +#else +  mw_debug_datav(buf, len, info, args); + +#endif +} + + + +void mw_mailme_data(const guchar *buf, gsize len, +		    const char *info, ...) { +  va_list args; +  va_start(args, info); +  mw_mailme_datav(buf, len, info, args); +  va_end(args); +} + + + +void mw_mailme_opaquev(struct mwOpaque *o, const char *info, va_list args) { +  mw_mailme_datav(o->data, o->len, info, args); +} + + + +void mw_mailme_opaque(struct mwOpaque *o, const char *info, ...) { +  va_list args; +  va_start(args, info); +  mw_mailme_opaquev(o, info, args); +  va_end(args); +} diff --git a/protocols/Sametime/src/meanwhile/src/mw_debug.h b/protocols/Sametime/src/meanwhile/src/mw_debug.h new file mode 100644 index 0000000000..acd7455eec --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_debug.h @@ -0,0 +1,130 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_DEBUG_H +#define _MW_DEBUG_H + + +#include <stdarg.h> +#include <glib.h> + +#include "mw_common.h" + + +/** replaces NULL strings with "(null)". useful for printf where +    you're unsure that the %s will be non-NULL. Note that while the +    linux printf will do this automatically, not all will. The others +    will instead segfault */ +#define NSTR(str) ((str)? (str): "(null)") + + +// Miranda NG adaptation, MSVC +// #ifndef g_debug +// #define g_debug(format...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format) +// #endif + + +// Miranda NG adaptation, MSVC +// #ifndef g_info +// #define g_info(format...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format) +// #endif + + +#ifndef MW_MAILME_ADDRESS +/** email address used in mw_debug_mailme. */ +#define MW_MAILME_ADDRESS  "meanwhile-devel@lists.sourceforge.net" +#endif + + +#ifndef MW_MAILME_CUT_START +#define MW_MAILME_CUT_START  "-------- begin copy --------" +#endif + + +#ifndef MW_MAILME_CUT_STOP +#define MW_MAILME_CUT_STOP   "--------- end copy ---------" +#endif + + +#ifndef MW_MAILME_MESSAGE +/** message used in mw_debug_mailme instructing user on what to do +    with the debugging output produced from that function */ +#define MW_MAILME_MESSAGE "\n" \ + "  Greetings! It seems that you've run across protocol data that the\n" \ + "Meanwhile library does not yet know about. As such, there may be\n"    \ + "some unexpected behaviour in this session. If you'd like to help\n"    \ + "resolve this issue, please copy and paste the following block into\n"  \ + "an email to the address listed below with a brief explanation of\n"    \ + "what you were doing at the time of this message. Thanks a lot!" +#endif + + +void mw_debug_datav(const guchar *buf, gsize len, +		    const char *info, va_list args); + + +void mw_debug_data(const guchar *buf, gsize len, +		   const char *info, ...); + + +void mw_debug_opaquev(struct mwOpaque *o, const char *info, va_list args); + + +void mw_debug_opaque(struct mwOpaque *o, const char *info, ...); + + +void mw_mailme_datav(const guchar *buf, gsize len, +		     const char *info, va_list args); + +void mw_mailme_data(const guchar *buf, gsize len, +		    const char *info, ...); + + +/** Outputs a hex dump of a mwOpaque with debugging info and a +    pre-defined message. Identical to mw_mailme_opaque, but taking a +    va_list argument */ +void mw_mailme_opaquev(struct mwOpaque *o, const char *info, va_list args); + + + +/** Outputs a hex dump of a mwOpaque with debugging info and a +    pre-defined message. + +    if MW_MAILME is undefined or false, this function acts the same as +    mw_mailme_opaque. + +    @arg block  data to be printed in a hex block +    @arg info   a printf-style format string + +    The resulting message is in the following format: +    @code +    MW_MAILME_MESSAGE +    " Please send mail to: " MW_MAILME_ADDRESS +    MW_MAILME_CUT_START +    info +    block +    MW_MAILME_CUT_STOP +    @endcode + */ +void mw_mailme_opaque(struct mwOpaque *o, const char *info, ...); + + +#endif + diff --git a/protocols/Sametime/src/meanwhile/src/mw_error.h b/protocols/Sametime/src/meanwhile/src/mw_error.h new file mode 100644 index 0000000000..6345358561 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_error.h @@ -0,0 +1,174 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_ERROR_H +#define _MW_ERROR_H + + +/** @file mw_error.h + +    Common error code constants used by Meanwhile. + +    Not all of these error codes (or even many, really) will ever +    actually appear from Meanwhile. These are taken directly from the +    houri draft, along with the minimal explanation for each. +*/ + + +#include <glib.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** reference to a new string appropriate for the given error code.*/ +char* mwError(guint32 code); + + +/* 8.3 Constants */ +/* 8.3.1 Error Codes */ +/* 8.3.1.1 General error/success codes */ + +/** @enum ERR_GENERAL +    general error codes */ +enum ERR_GENERAL { +  ERR_SUCCESS                = 0x00000000, +  ERR_FAILURE                = 0x80000000, +  ERR_REQUEST_DELAY          = 0x00000001, +  ERR_REQUEST_INVALID        = 0x80000001, +  ERR_NOT_LOGGED_IN          = 0x80000002, +  ERR_NOT_AUTHORIZED         = 0x80000003, +  ERR_ABORT                  = 0x80000004, +  ERR_NO_ELEMENT             = 0x80000005, +  ERR_NO_USER                = 0x80000006, +  ERR_BAD_DATA               = 0x80000007, +  ERR_NOT_IMPLEMENTED        = 0x80000008, +  ERR_UNKNOWN_ERROR          = 0x80000009, /* what is this? */ +  ERR_STARVING               = 0x8000000a, +  ERR_CHANNEL_NO_SUPPORT     = 0x8000000b, +  ERR_CHANNEL_EXISTS         = 0x8000000c, +  ERR_SERVICE_NO_SUPPORT     = 0x8000000d, +  ERR_PROTOCOL_NO_SUPPORT    = 0x8000000e, +  ERR_PROTOCOL_NO_SUPPORT2   = 0x8000000f, /* duplicate? */ +  ERR_VERSION_NO_SUPPORT     = 0x80000010, +  ERR_USER_SKETCHY           = 0x80000011, +  ERR_ALREADY_INITIALIZED    = 0x80000013, +  ERR_NOT_OWNER              = 0x80000014, +  ERR_TOKEN_INVALID          = 0x80000015, +  ERR_TOKEN_EXPIRED          = 0x80000016, +  ERR_TOKEN_IP_MISMATCH      = 0x80000017, +  ERR_PORT_IN_USE            = 0x80000018, +  ERR_NETWORK_DEAD           = 0x80000019, +  ERR_NO_MASTER_CHANNEL      = 0x8000001a, +  ERR_ALREADY_SUBSCRIBED     = 0x8000001b, +  ERR_NOT_SUBSCRIBED         = 0x8000001c, +  ERR_ENCRYPT_NO_SUPPORT     = 0x8000001d, +  ERR_ENCRYPT_UNINITIALIZED  = 0x8000001e, +  ERR_ENCRYPT_UNACCEPTABLE   = 0x8000001f, +  ERR_ENCRYPT_INVALID        = 0x80000020, +  ERR_NO_COMMON_ENCRYPT      = 0x80000021, +  ERR_CHANNEL_DESTROYED      = 0x80000022, +  ERR_CHANNEL_REDIRECTED     = 0x80000023 +}; + + +/* 8.3.1.2 Connection/disconnection errors */ + +#define VERSION_MISMATCH     0x80000200 +#define INSUF_BUFFER         0x80000201 +#define NOT_IN_USE           0x80000202 +#define INSUF_SOCKET         0x80000203 +#define HARDWARE_ERROR       0x80000204 +#define NETWORK_DOWN         0x80000205 +#define HOST_DOWN            0x80000206 +#define HOST_UNREACHABLE     0x80000207 +#define TCPIP_ERROR          0x80000208 +#define FAT_MESSAGE          0x80000209 +#define PROXY_ERROR          0x8000020A +#define SERVER_FULL          0x8000020B +#define SERVER_NORESPOND     0x8000020C +#define CANT_CONNECT         0x8000020D +#define USER_REMOVED         0x8000020E +#define PROTOCOL_ERROR       0x8000020F +#define USER_RESTRICTED      0x80000210 +#define INCORRECT_LOGIN      0x80000211 +#define ENCRYPT_MISMATCH     0x80000212 +#define USER_UNREGISTERED    0x80000213 +#define VERIFICATION_DOWN    0x80000214 +#define USER_TOO_IDLE        0x80000216 +#define GUEST_IN_USE         0x80000217 +#define USER_EXISTS          0x80000218 +#define USER_RE_LOGIN        0x80000219 +#define BAD_NAME             0x8000021A +#define REG_MODE_NS          0x8000021B +#define WRONG_USER_PRIV      0x8000021C +#define NEED_EMAIL           0x8000021D +#define DNS_ERROR            0x8000021E +#define DNS_FATAL_ERROR      0x8000021F +#define DNS_NOT_FOUND        0x80000220 +#define CONNECTION_BROKEN    0x80000221 +#define CONNECTION_ABORTED   0x80000222 +#define CONNECTION_REFUSED   0x80000223 +#define CONNECTION_RESET     0x80000224 +#define CONNECTION_TIMED     0x80000225 +#define CONNECTION_CLOSED    0x80000226 +#define MULTI_SERVER_LOGIN   0x80000227 +#define MULTI_SERVER_LOGIN2  0x80000228 +#define MULTI_LOGIN_COMP     0x80000229 +#define MUTLI_LOGIN_ALREADY  0x8000022A +#define SERVER_BROKEN        0x8000022B +#define SERVER_PATH_OLD      0x8000022C +#define APPLET_LOGOUT        0x8000022D + + +/* 8.3.1.3 Client error codes */ + +/** @enum ERR_CLIENT +    Client error codes */ +enum ERR_CLIENT { +  ERR_CLIENT_USER_GONE       = 0x80002000, /* user isn't here */ +  ERR_CLIENT_USER_DND        = 0x80002001, /* user is DND */ +  ERR_CLIENT_USER_ELSEWHERE  = 0x80002002, /* already logged in elsewhere */ +}; + + +/* 8.3.1.4 IM error codes */ + +/** @enum ERR_IM +    IM error codes */ +enum ERR_IM { +  ERR_IM_COULDNT_REGISTER    = 0x80002003, +  ERR_IM_ALREADY_REGISTERED  = 0x80002004, + +  /** apparently, this is used to mean that the requested feature (per +      the channel create addtl data) is not supported by the client on +      the other end of the IM channel */ +  ERR_IM_NOT_REGISTERED      = 0x80002005, +}; + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_ERROR_H */ diff --git a/protocols/Sametime/src/meanwhile/src/mw_message.h b/protocols/Sametime/src/meanwhile/src/mw_message.h new file mode 100644 index 0000000000..8402b8b7ee --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_message.h @@ -0,0 +1,305 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_MESSAGE_H +#define _MW_MESSAGE_H + + +#include <glib/glist.h> +#include "mw_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Cast a pointer to a message subtype (eg, mwMsgHandshake, +    mwMsgAdmin) into a pointer to a mwMessage */ +#define MW_MESSAGE(msg) (&msg->head) + + +/** Indicates the type of a message. */ +enum mwMessageType { +  mwMessage_HANDSHAKE         = 0x0000,  /**< mwMsgHandshake */ +  mwMessage_HANDSHAKE_ACK     = 0x8000,  /**< mwMsgHandshakeAck */ +  mwMessage_LOGIN             = 0x0001,  /**< mwMsgLogin */ +  mwMessage_LOGIN_ACK         = 0x8001,  /**< mwMsgLoginAck */ +  mwMessage_LOGIN_REDIRECT    = 0x0018,  /**< mwMsgLoginRedirect */ +  mwMessage_LOGIN_CONTINUE    = 0x0016,  /**< mwMsgLoginContinue */ + +  mwMessage_CHANNEL_CREATE    = 0x0002,  /**< mwMsgChannelCreate */ +  mwMessage_CHANNEL_DESTROY   = 0x0003,  /**< mwMsgChannelDestroy */ +  mwMessage_CHANNEL_SEND      = 0x0004,  /**< mwMsgChannelSend */ +  mwMessage_CHANNEL_ACCEPT    = 0x0006,  /**< mwMsgChannelAccept */ + +  mwMessage_SET_USER_STATUS   = 0x0009,  /**< mwMsgSetUserStatus */ +  mwMessage_SET_PRIVACY_LIST  = 0x000b,  /**< mwMsgSetPrivacyList */ +  mwMessage_SENSE_SERVICE     = 0x0011,  /**< mwMsgSenseService */ +  mwMessage_ADMIN             = 0x0019,  /**< mwMsgAdmin */ +  mwMessage_ANNOUNCE          = 0x0022,  /**< mwMsgAnnounce */ +}; + + +enum mwMessageOption { +  mwMessageOption_ENCRYPT      = 0x4000,  /**< message data is encrypted */ +  mwMessageOption_HAS_ATTRIBS  = 0x8000,  /**< message has attributes */ +}; + + +/** @see mwMessageOption */ +#define MW_MESSAGE_HAS_OPTION(msg, opt) \ +  ((msg)->options & (opt)) + + +struct mwMessage { +  guint16 type;     /**< @see mwMessageType */ +  guint16 options;  /**< @see mwMessageOption */ +  guint32 channel;  /**< ID of channel message is intended for */ +  struct mwOpaque attribs;  /**< optional message attributes */ +}; + + + +/** Allocate and initialize a new message of the specified type */ +struct mwMessage *mwMessage_new(enum mwMessageType type); + + +/** build a message from its representation */ +struct mwMessage *mwMessage_get(struct mwGetBuffer *b); + + +void mwMessage_put(struct mwPutBuffer *b, struct mwMessage *msg); + + +void mwMessage_free(struct mwMessage *msg); + + +/* 8.4 Messages */ +/* 8.4.1 Basic Community Messages */ +/* 8.4.1.1 Handshake */ + +struct mwMsgHandshake { +  struct mwMessage head; +  guint16 major;          /**< client's major version number */ +  guint16 minor;          /**< client's minor version number */ +  guint32 srvrcalc_addr;  /**< 0.0.0.0 */ +  guint16 login_type;     /**< @see mwLoginType */ +  guint32 loclcalc_addr;  /**< local public IP */ +  guint16 unknown_a;      /**< normally 0x0100 */ +  guint32 unknown_b;      /**< normally 0x00000000 */ +  char *local_host;       /**< name of client host */ +}; + + +/* 8.4.1.2 HandshakeAck */ + +struct mwMsgHandshakeAck { +  struct mwMessage head; +  guint16 major;          /**< server's major version number */ +  guint16 minor;          /**< server's minor version number */ +  guint32 srvrcalc_addr;  /**< server-calculated address */ +  guint32 magic;          /**< four bytes of something */ +  struct mwOpaque data;   /**< server's DH public key for auth */ +}; + + +/* 8.3.7 Authentication Types */ + +enum mwAuthType { +  mwAuthType_PLAIN    = 0x0000, +  mwAuthType_TOKEN    = 0x0001, +  mwAuthType_ENCRYPT  = 0x0002, /**< @todo remove for 1.0 */ +  mwAuthType_RC2_40   = 0x0002, +  mwAuthType_RC2_128  = 0x0004, +}; + + +/* 8.4.1.3 Login */ + +struct mwMsgLogin { +  struct mwMessage head; +  guint16 login_type;         /**< @see mwLoginType */ +  char *name;                 /**< user identification */ +  guint16 auth_type;          /**< @see mwAuthType */ +  struct mwOpaque auth_data;  /**< authentication data */ +}; + + +/* 8.4.1.4 LoginAck */ + +struct mwMsgLoginAck { +  struct mwMessage head; +  struct mwLoginInfo login; +  struct mwPrivacyInfo privacy; +  struct mwUserStatus status; +}; + + +/* 8.4.1.5 LoginCont */ + +struct mwMsgLoginContinue { +  struct mwMessage head; +}; + + +/* 8.4.1.6 AuthPassed */ + +struct mwMsgLoginRedirect { +  struct mwMessage head; +  char *host; +  char *server_id; +}; + + +/* 8.4.1.7 CreateCnl */ + +/** an offer of encryption items */ +struct mwEncryptOffer { +  guint16 mode;   /**< encryption mode */ +  GList *items;   /**< list of mwEncryptItem offered */ +  guint16 extra;  /**< encryption mode again? */ +  gboolean flag;  /**< unknown flag */ +}; + + +struct mwMsgChannelCreate { +  struct mwMessage head; +  guint32 reserved;         /**< unknown reserved data */ +  guint32 channel;          /**< intended ID for new channel */ +  struct mwIdBlock target;  /**< User ID. for service use */ +  guint32 service;          /**< ID for the target service */ +  guint32 proto_type;       /**< protocol type for the service */ +  guint32 proto_ver;        /**< protocol version for the service */ +  guint32 options;          /**< options */ +  struct mwOpaque addtl;    /**< service-specific additional data */ +  gboolean creator_flag;    /**< indicate presence of creator information */ +  struct mwLoginInfo creator; +  struct mwEncryptOffer encrypt; +}; + + +/* 8.4.1.8 AcceptCnl */ + +/** a selected encryption item from those offered */ +struct mwEncryptAccept { +  guint16 mode;                /**< encryption mode */ +  struct mwEncryptItem *item;  /**< chosen mwEncryptItem (optional) */ +  guint16 extra;               /**< encryption mode again? */ +  gboolean flag;               /**< unknown flag */ +}; + + +struct mwMsgChannelAccept { +  struct mwMessage head; +  guint32 service;         /**< ID for the channel's service */ +  guint32 proto_type;      /**< protocol type for the service */ +  guint32 proto_ver;       /**< protocol version for the service */ +  struct mwOpaque addtl;   /**< service-specific additional data */ +  gboolean acceptor_flag;  /**< indicate presence of acceptor information */ +  struct mwLoginInfo acceptor; +  struct mwEncryptAccept encrypt; +}; + + +/* 8.4.1.9 SendOnCnl */ + +struct mwMsgChannelSend { +  struct mwMessage head; + +  /** message type. each service defines its own send types. Type IDs +      are only necessarily unique within a given service. */ +  guint16 type; + +  /** protocol data to be interpreted by the handling service */ +  struct mwOpaque data; +}; + + +/* 8.4.1.10 DestroyCnl */ + +struct mwMsgChannelDestroy { +  struct mwMessage head; +  guint32 reason;        /**< reason for closing the channel. */ +  struct mwOpaque data;  /**< additional information */ +}; + + +/* 8.4.1.11 SetUserStatus */ + +struct mwMsgSetUserStatus { +  struct mwMessage head; +  struct mwUserStatus status; +}; + + +/* 8.4.1.12 SetPrivacyList */ + +struct mwMsgSetPrivacyList { +  struct mwMessage head; +  struct mwPrivacyInfo privacy; +}; + + +/* Sense Service */ + +/** Sent to the server to request the presense of a service by its +    ID. Sent to the client to indicate the presense of such a +    service */ +struct mwMsgSenseService { +  struct mwMessage head; +  guint32 service; +}; + + +/* Admin */ + +/** An administrative broadcast message */ +struct mwMsgAdmin { +  struct mwMessage head; +  char *text; +}; + + +/* Announce */ + +/** An announcement between users */ +struct mwMsgAnnounce { +  struct mwMessage head; +  gboolean sender_present;    /**< indicates presence of sender data */ +  struct mwLoginInfo sender;  /**< who sent the announcement */ +  guint16 unknown_a;          /**< unknown A. Usually 0x00 */ +  gboolean may_reply;         /**< replies allowed */ +  char *text;                 /**< text of message */ + +  /** list of (char *) indicating recipients. Recipient users are in +      the format "@U username" and recipient NAB groups are in the +      format "@G groupname" */ +  GList *recipients; +}; + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_MESSAGE_H */ + diff --git a/protocols/Sametime/src/meanwhile/src/mw_service.h b/protocols/Sametime/src/meanwhile/src/mw_service.h new file mode 100644 index 0000000000..9bcd6509db --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_service.h @@ -0,0 +1,370 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_SERVICE_H +#define _MW_SERVICE_H + + +#include "mw_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* place-holders */ +struct mwChannel; +struct mwService; +struct mwSession; +struct mwMsgChannelCreate; +struct mwMsgChannelAccept; +struct mwMsgChannelDestroy; + + +/** State-tracking for a service */ +enum mwServiceState { +  mwServiceState_STOPPED,   /**< the service is not active */ +  mwServiceState_STOPPING,  /**< the service is shutting down */ +  mwServiceState_STARTED,   /**< the service is active */ +  mwServiceState_STARTING,  /**< the service is starting up */ +  mwServiceState_ERROR,     /**< error in service, shutting down */ +  mwServiceState_UNKNOWN,   /**< error determining state */ +}; + + +/** Casts a concrete service (such as mwServiceAware) into a mwService */ +#define MW_SERVICE(srv) ((struct mwService *) srv) + + +#define MW_SERVICE_IS_STATE(srvc, state) \ +  (mwService_getState(MW_SERVICE(srvc)) == (state)) + +#define MW_SERVICE_IS_STOPPED(srvc)  \ +  MW_SERVICE_IS_STATE(srvc, mwServiceState_STOPPED) + +#define MW_SERVICE_IS_STOPPING(srvc) \ +  MW_SERVICE_IS_STATE(srvc, mwServiceState_STOPPING) + +#define MW_SERVICE_IS_STARTED(srvc)  \ +  MW_SERVICE_IS_STATE(srvc, mwServiceState_STARTED) + +#define MW_SERVICE_IS_STARTING(srvc) \ +  MW_SERVICE_IS_STATE(srvc, mwServiceState_STARTING) + + +/** If a service is STARTING or STARTED, it's considered LIVE */ +#define MW_SERVICE_IS_LIVE(srvc) \ +  (MW_SERVICE_IS_STARTING(srvc) || MW_SERVICE_IS_STARTED(srvc)) + +/** If a service is STOPPING or STOPPED, it's considered DEAD */ +#define MW_SERVICE_IS_DEAD(srvc) \ +  (MW_SERVICE_IS_STOPPING(srvc) || MW_SERVICE_IS_STOPPED(srvc)) + + +typedef void (*mwService_funcStart)(struct mwService *service); + +typedef void (*mwService_funcStop)(struct mwService *service); + +typedef void (*mwService_funcClear)(struct mwService *service); + +typedef const char *(*mwService_funcGetName)(struct mwService *service); + +typedef const char *(*mwService_funcGetDesc)(struct mwService *service); + +/** @todo remove msg and replace with appropriate additional parameters */ +typedef void (*mwService_funcRecvCreate) +     (struct mwService *service, +      struct mwChannel *channel, +      struct mwMsgChannelCreate *msg); + +/** @todo remove msg and replace with appropriate additional parameters */ +typedef void (*mwService_funcRecvAccept) +     (struct mwService *service, +      struct mwChannel *channel, +      struct mwMsgChannelAccept *msg); + +/** @todo remove msg and replace with appropriate additional parameters */ +typedef void (*mwService_funcRecvDestroy) +     (struct mwService *service, +      struct mwChannel *channel, +      struct mwMsgChannelDestroy *msg); + +typedef void (*mwService_funcRecv) +     (struct mwService *service, +      struct mwChannel *channel, +      guint16 msg_type, +      struct mwOpaque *data); + + +/** A service is the recipient of sendOnCnl messages sent over +    channels marked with the corresponding service id. Services +    provide functionality such as IM relaying, Awareness tracking and +    notification, and Conference handling.  It is a service's +    responsibility to accept or destroy channels, and to process data +    sent over those channels */ +struct mwService { + +  /** the unique identifier by which this service is registered. The +      type value also relates to those channels which will be directed +      to this service */ +  guint32 type; + +  /** the state of this service. Determines whether or not the session +      should call the start function upon receipt of a service +      available message. Should not be set or checked by hand. + +      @relates mwService_getState */ +  enum mwServiceState state; + +  /** session this service is attached to. +      @relates mwService_getSession */ +  struct mwSession *session; + +  /** @return string short name of the service +      @relates mwService_getName */ +  mwService_funcGetName get_name; + +  /** @return string short description of the service +      @relates mwService_getDesc */ +  mwService_funcGetDesc get_desc; + +  /** The service's channel create handler. Called when the session +      receives a channel create message with a service matching this +      service's type. + +      @relates mwService_recvCreate */ +  mwService_funcRecvCreate recv_create; + +  /** The service's channel accept handler. Called when the session +      receives a channel accept message for a channel with a service +      matching this service's type. + +      @relates mwService_recvAccept */ +  mwService_funcRecvAccept recv_accept; + +  /** The service's channel destroy handler. Called when the session +      receives a channel destroy message for a channel with a service +      matching this service's type. + +      @relates mwService_recvDestroy */ +  mwService_funcRecvDestroy recv_destroy; + +  /** The service's input handler. Called when the session receives +      data on a channel belonging to this service + +      @relates mwService_recv */ +  mwService_funcRecv recv; + +  /** The service's start handler. Called upon the receipt of a +      service available message. + +      @relates mwService_start */ +  mwService_funcStart start; + +  /** The service's stop handler. Called when the session is shutting +      down, or when the service is free'd. + +      @relates mwService_stop */ +  mwService_funcStop stop; +   +  /** The service's cleanup handler. Service implementations should +      presume that mwService::stop will be called first. The clear +      handler is not for shutting down channels or generating +      non-cleanup side-effects, it is only for handling tear-down of +      the service, and will only be called once for any instance. + +      @relates mwService_free */ +  mwService_funcClear clear; + +  /** Optional client data, not for use by service implementations + +      @relates mwService_getClientData +      @relates mwService_setClientData */ +  gpointer client_data; + +  /** Optional client data cleanup function. Called with client_data +      from mwService_free + +      @relates mwService_getClientData +      @relates mwService_setClientData */ +  GDestroyNotify client_cleanup; +}; + + +/** @name Service Extension API + +    These functions are for use by service implementations */ +/*@{*/ + + +/** Prepares a newly allocated service for use. +     +    Intended for use by service implementations, rather than by code +    utilizing a service. +     +    The service state will be initialized to STOPPED. +     +    @param service       the service to initialize +    @param session       the service's owning session +    @param service_type  the service ID number */ +void mwService_init(struct mwService *service, +		    struct mwSession *session, +		    guint32 service_type); + + +/** Indicate that a service is started. To be used by service +    implementations when the service is fully started. */ +void mwService_started(struct mwService *service); + + +/** Indicate that a service is stopped. To be used by service +    implementations when the service is fully stopped. */ +void mwService_stopped(struct mwService *service); + + +/*@}*/ + + +/** @name General Services API + +    These functions provide unified access to the general functions of +    a client service, with some simple sanity-checking. */ +/*@{*/ + + +/** Triggers the recv_create handler on the service. + +    @param service  the service to handle the message +    @param channel  the channel being created +    @param msg      the channel create message */ +void mwService_recvCreate(struct mwService *service, +			  struct mwChannel *channel, +			  struct mwMsgChannelCreate *msg); + + +/** Triggers the recv_accept handler on the service. + +    @param service  the service to handle the message +    @param channel  the channel being accepted +    @param msg      the channel accept message */ +void mwService_recvAccept(struct mwService *service, +			  struct mwChannel *channel, +			  struct mwMsgChannelAccept *msg); + + +/** Triggers the recv_destroy handler on the service. + +    @param service  the service to handle the message +    @param channel  the channel being destroyed +    @param msg      the channel destroy message */ +void mwService_recvDestroy(struct mwService *service, +			   struct mwChannel *channel, +			   struct mwMsgChannelDestroy *msg); + + +/** Triggers the input handler on the service + +    @param service   the service to receive the input +    @param channel   the channel the input was received from +    @param msg_type  the service-dependant message type +    @param data      the message data */ +void mwService_recv(struct mwService *service, +		    struct mwChannel *channel, +		    guint16 msg_type, +		    struct mwOpaque *data); + + +/** @return the appropriate type id for the service */ +guint32 mwService_getType(struct mwService *); + + +/** @return string short name of the service */ +const char *mwService_getName(struct mwService *); + + +/** @return string short description of the service */ +const char *mwService_getDesc(struct mwService *); + + +/** @return the service's session */ +struct mwSession *mwService_getSession(struct mwService *service); + + +/** @returns the service's state +*/ +enum mwServiceState mwService_getState(struct mwService *service); + + +/** Triggers the start handler for the service. Normally called from +    the session upon receipt of a service available message. Service +    implementations should use this handler to open any necessary +    channels, etc. Checks that the service is STOPPED, or returns. +     +    @param service The service to start +*/ +void mwService_start(struct mwService *service); + + +/** Triggers the stop handler for the service. Normally called from +    the session before closing down the connection. Checks that the +    service is STARTED or STARTING, or returns + +    @param service The service to stop +*/ +void mwService_stop(struct mwService *service); + + +/** Frees memory used by a service. Will trigger the stop handler if +    the service is STARTED or STARTING. Triggers clear handler to allow +    cleanup. + +    @param service The service to clear and free +*/ +void mwService_free(struct mwService *service); + + +/** Associates client data with service. If there is existing data, it +    will not have its cleanup function called. Client data is not for +    use by service implementations. Rather, it is for use by client +    code which may later make use of those service implementations. */ +void mwService_setClientData(struct mwService *service, +			     gpointer data, GDestroyNotify cleanup); + + +/** Reference associated client data */ +gpointer mwService_getClientData(struct mwService *service); + + +/** Removes client data from service. If there is a cleanup function, +    it will be called. */ +void mwService_removeClientData(struct mwService *service); + + +/*@}*/ + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_SERVICE_H */ + diff --git a/protocols/Sametime/src/meanwhile/src/mw_session.h b/protocols/Sametime/src/meanwhile/src/mw_session.h new file mode 100644 index 0000000000..e606e0ca98 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_session.h @@ -0,0 +1,397 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_SESSION_H +#define _MW_SESSION_H + + +/** @file mw_session.h + +    A client session with a Sametime server is encapsulated in the +    mwSession structure. The session controls channels, provides +    encryption ciphers, and manages services using messages over the +    Master channel. + +    A session does not directly communicate with a socket or stream, +    instead the session is initialized from client code with an +    instance of a mwSessionHandler structure. This session handler +    provides functions as call-backs for common session events, and +    provides functions for writing-to and closing the connection to +    the server. + +    A session does not perform reads on a socket directly. Instead, it +    must be fed from an outside source via the mwSession_recv +    function. The session will buffer and merge data passed to this +    function to build complete protocol messages, and will act upon +    each complete message accordingly. +*/ + + +#include "mw_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +struct mwChannelSet; +struct mwCipher; +struct mwMessage; +struct mwService; + + +/** default protocol major version */ +#define MW_PROTOCOL_VERSION_MAJOR  0x001e + + +/** default protocol minor version */ +#define MW_PROTOCOL_VERSION_MINOR  0x001d + + +/** @section Session Properties +    for use with mwSession_setProperty, et al. +*/ +/*@{*/ + +/** char *, session user ID */ +#define mwSession_AUTH_USER_ID      "session.auth.user" + +/** char *, plaintext password */ +#define mwSession_AUTH_PASSWORD     "session.auth.password" + +/** struct mwOpaque *, authentication token */ +#define mwSession_AUTH_TOKEN        "session.auth.token" + +/** char *, hostname of client */ +#define mwSession_CLIENT_HOST       "client.host" + +/** guint32, local IP of client */ +#define mwSession_CLIENT_IP         "client.ip" + +/** guint16, major version of client protocol */ +#define mwSession_CLIENT_VER_MAJOR  "client.version.major" + +/** guint16, minor version of client protocol */ +#define mwSession_CLIENT_VER_MINOR  "client.version.minor" + +/** guint16, client type identifier */ +#define mwSession_CLIENT_TYPE_ID    "client.id" + +/** guint16, major version of server protocol */ +#define mwSession_SERVER_VER_MAJOR  "server.version.major" + +/** guint16, minor version of server protocol */ +#define mwSession_SERVER_VER_MINOR  "server.version.minor" + +/*@}*/ + + +enum mwSessionState { +  mwSession_STARTING,      /**< session is starting */ +  mwSession_HANDSHAKE,     /**< session has sent handshake */ +  mwSession_HANDSHAKE_ACK, /**< session has received handshake ack */ +  mwSession_LOGIN,         /**< session has sent login */ +  mwSession_LOGIN_REDIR,   /**< session has been redirected */ +  mwSession_LOGIN_ACK,     /**< session has received login ack */ +  mwSession_STARTED,       /**< session is active */ +  mwSession_STOPPING,      /**< session is shutting down */ +  mwSession_STOPPED,       /**< session is stopped */ +  mwSession_UNKNOWN,       /**< indicates an error determining state */ +  mwSession_LOGIN_CONT,    /**< session has sent a login continue */ +}; + + +#define mwSession_isState(session, state) \ +  (mwSession_getState((session)) == (state)) + +#define mwSession_isStarting(s) \ +  (mwSession_isState((s), mwSession_STARTING)  || \ +   mwSession_isState((s), mwSession_HANDSHAKE) || \ +   mwSession_isState((s), mwSession_HANDSHAKE_ACK) || \ +   mwSession_isState((s), mwSession_LOGIN) || \ +   mwSession_isState((s), mwSession_LOGIN_ACK) || \ +   mwSession_isState((s), mwSession_LOGIN_REDIR) || \ +   mwSession_isState((s), mwSession_LOGIN_CONT)) + +#define mwSession_isStarted(s) \ +  (mwSession_isState((s), mwSession_STARTED)) + +#define mwSession_isStopping(s) \ +  (mwSession_isState((s), mwSession_STOPPING)) + +#define mwSession_isStopped(s) \ +  (mwSession_isState((s), mwSession_STOPPED)) + + +/** @struct mwSession + +    Represents a Sametime client session */ +struct mwSession; + + +/** @struct mwSessionHandler + +    session handler. Structure which interfaces a session with client +    code to provide I/O and event handling */ +struct mwSessionHandler { +   +  /** write data to the server connection. Required. Should return +      zero for success, non-zero for error */ +  int (*io_write)(struct mwSession *, const guchar *buf, gsize len); +   +  /** close the server connection. Required */ +  void (*io_close)(struct mwSession *); + +  /** triggered by mwSession_free. Optional. Put cleanup code here */ +  void (*clear)(struct mwSession *); + +  /** Called when the session has changed status. + +      @see mwSession_getStateInfo for uses of info field + +      @param s      the session +      @param state  the session's state +      @param info   additional state information */ +  void (*on_stateChange)(struct mwSession *s, +			 enum mwSessionState state, gpointer info); + +  /** called when privacy information has been sent or received + +      @see mwSession_getPrivacyInfo +  */ +  void (*on_setPrivacyInfo)(struct mwSession *); + +  /** called when user status has changed + +      @see mwSession_getUserStatus */ +  void (*on_setUserStatus)(struct mwSession *); + +  /** called when an admin messages has been received */ +  void (*on_admin)(struct mwSession *, const char *text); + +  /** called when an announcement arrives */ +  void (*on_announce)(struct mwSession *, struct mwLoginInfo *from, +		      gboolean may_reply, const char *text); + +}; + + +/** allocate a new session */ +struct mwSession *mwSession_new(struct mwSessionHandler *); + + +/** stop, clear, free a session. Does not free contained ciphers or +    services, these must be taken care of explicitly. */ +void mwSession_free(struct mwSession *); + + +/** obtain a reference to the session's handler */ +struct mwSessionHandler *mwSession_getHandler(struct mwSession *); + + +/** instruct the session to begin. This will result in the initial +    handshake message being sent. */ +void mwSession_start(struct mwSession *); + + +/** instruct the session to shut down with the following reason +    code. */ +void mwSession_stop(struct mwSession *, guint32 reason); + + +/** Data is buffered, unpacked, and parsed into a message, then +    processed accordingly. */ +void mwSession_recv(struct mwSession *, const guchar *, gsize); + + +/** primarily used by services to have messages serialized and sent +    @param s    session to send message over +    @param msg  message to serialize and send +    @returns    0 for success */ +int mwSession_send(struct mwSession *s, struct mwMessage *msg); + + +/** sends the keepalive byte */ +int mwSession_sendKeepalive(struct mwSession *s); + + +/** respond to a login redirect message by forcing the login sequence +    to continue through the immediate server. */ +int mwSession_forceLogin(struct mwSession *s); + + +/** send an announcement to a list of users/groups. Targets of +    announcement must be in the same community as the session. + +    @param s          session to send announcement from +    @param may_reply  permit clients to reply. Not all clients honor this. +    @param text       text of announcement +    @param recipients list of recipients. Each recipient is specified +                      by a single string, prefix with "@U " for users +                      and "@G " for Notes Address Book groups. +*/ +int mwSession_sendAnnounce(struct mwSession *s, gboolean may_reply, +			   const char *text, const GList *recipients); + + +/** set the internal privacy information, and inform the server as +    necessary. Triggers the on_setPrivacyInfo call-back. */ +int mwSession_setPrivacyInfo(struct mwSession *, struct mwPrivacyInfo *); + + +/** direct reference to the session's internal privacy structure */ +struct mwPrivacyInfo *mwSession_getPrivacyInfo(struct mwSession *); + + +/** reference the login information for the session */ +struct mwLoginInfo *mwSession_getLoginInfo(struct mwSession *); + + +/** set the internal user status state, and inform the server as +    necessary. Triggers the on_setUserStatus call-back */ +int mwSession_setUserStatus(struct mwSession *, struct mwUserStatus *); + + +struct mwUserStatus *mwSession_getUserStatus(struct mwSession *); + + +/** current status of the session */ +enum mwSessionState mwSession_getState(struct mwSession *); + + +/** additional status-specific information. Depending on the state of +    the session, this value has different meaning. + +    @li @c mwSession_STOPPING guint32 error code causing +    the session to shut down + +    @li @c mwSession_STOPPED guint32 error code causing +    the session to shut down + +    @li @c mwSession_LOGIN_REDIR (char *) host to redirect +    to +*/ +gpointer mwSession_getStateInfo(struct mwSession *); + + +struct mwChannelSet *mwSession_getChannels(struct mwSession *); + + +/** adds a service to the session. If the session is started (or when +    the session is successfully started) and the service has a start +    function, the session will request service availability from the +    server. On receipt of the service availability notification, the +    session will call the service's start function. + +    @return TRUE if the session was added correctly */ +gboolean mwSession_addService(struct mwSession *, struct mwService *); + + +/** find a service by its type identifier */ +struct mwService *mwSession_getService(struct mwSession *, guint32 type); + + +/** removes a service from the session. If the session is started and +    the service has a stop function, it will be called. Returns the +    removed service */ +struct mwService *mwSession_removeService(struct mwSession *, guint32 type); + + +/** a GList of services in this session. The GList needs to be freed +    after use */ +GList *mwSession_getServices(struct mwSession *); + + +/** instruct a STARTED session to check the server for the presense of +    a given service. The service will be automatically started upon +    receipt of an affirmative reply from the server. This function is +    automatically called upon all services in a session when the +    session is fully STARTED. + +    Services which terminate due to an error may call this on +    themselves to re-initialize when their server-side counterpart is +    made available again. + +    @param s     owning session +    @param type  service type ID */ +void mwSession_senseService(struct mwSession *s, guint32 type); + + +/** adds a cipher to the session. */ +gboolean mwSession_addCipher(struct mwSession *, struct mwCipher *); + + +/** find a cipher by its type identifier */ +struct mwCipher *mwSession_getCipher(struct mwSession *, guint16 type); + + +/** remove a cipher from the session */ +struct mwCipher *mwSession_removeCipher(struct mwSession *, guint16 type); + + +/** a GList of ciphers in this session. The GList needs to be freed +    after use */ +GList *mwSession_getCiphers(struct mwSession *); + + +/** associate a key:value pair with the session. If an existing value is +    associated with the same key, it will have its clear function called +    and will be replaced with the new value */ +void mwSession_setProperty(struct mwSession *, const char *key, +			   gpointer val, GDestroyNotify clear); + + +/** obtain the value of a previously set property, or NULL */ +gpointer mwSession_getProperty(struct mwSession *, const char *key); + + +/** remove a property, calling the optional GDestroyNotify function +    indicated in mwSession_setProperty if applicable */ +void mwSession_removeProperty(struct mwSession *, const char *key); + + +/** associate arbitrary data with the session for use by the client +    code. Only client applications should use this, never services. + +    @param session  the session to associate the data with +    @param data     arbitrary client data +    @param clear    optional cleanup function called on data from +                    mwSession_removeClientData and mwSession_free +*/ +void mwSession_setClientData(struct mwSession *session, +			     gpointer data, GDestroyNotify clear); + + +gpointer mwSession_getClientData(struct mwSession *session); + + +/** remove client data, calling the optional GDestroyNotify function +    indicated in mwSession_setClientData if applicable */ +void mwSession_removeClientData(struct mwSession *session); + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_SESSION_H */ + diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_aware.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_aware.h new file mode 100644 index 0000000000..0d5090d258 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_aware.h @@ -0,0 +1,289 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_SRVC_AWARE_H +#define _MW_SRVC_AWARE_H + + +/** @file mw_srvc_aware.h + +    The aware service... + +    @todo remove the whole idea of an instantiated mwAwareList and +    instead use arbitrary pointers (including NULL) as keys to +    internally stored lists. This removes the problem of the service +    free'ing its lists and invalidating mwAwareList references from +    client code. +*/ + + +#include "mw_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Type identifier for the aware service */ +#define mwService_AWARE  0x00000011 + + +/** @struct mwServiceAware + +    Instance of an Aware Service. The members of this structure are +    not made available. Accessing the parts of an aware service should +    be performed through the appropriate functions. Note that +    instances of this structure can be safely cast to a mwService. +*/ +struct mwServiceAware; + + +/** @struct mwAwareList + +    Instance of an Aware List. The members of this structure are not +    made available. Access to the parts of an aware list should be +    handled through the appropriate functions. + +    Any references to an aware list are rendered invalid when the +    parent service is free'd +*/ +struct mwAwareList; + + +/** @struct mwAwareAttribute + +    Key/Opaque pair indicating an identity's attribute. + */ +struct mwAwareAttribute; + + +/** Predefined keys appropriate for a mwAwareAttribute + */ +enum mwAwareAttributeKeys { +  mwAttribute_AV_PREFS_SET   = 0x01, /**< A/V prefs specified, gboolean */ +  mwAttribute_MICROPHONE     = 0x02, /**< has a microphone, gboolean */ +  mwAttribute_SPEAKERS       = 0x03, /**< has speakers, gboolean */ +  mwAttribute_VIDEO_CAMERA   = 0x04, /**< has a video camera, gboolean */ +  mwAttribute_FILE_TRANSFER  = 0x06, /**< supports file transfers, gboolean */ +}; + + +typedef void (*mwAwareAttributeHandler) +     (struct mwServiceAware *srvc, +      struct mwAwareAttribute *attrib); + + +struct mwAwareHandler { +  mwAwareAttributeHandler on_attrib; +  void (*clear)(struct mwServiceAware *srvc); +}; + + +/** Appropriate function type for the on-aware signal + +    @param list  mwAwareList emiting the signal +    @param id    awareness status information +    @param data  user-specified data +*/ +typedef void (*mwAwareSnapshotHandler) +     (struct mwAwareList *list, +      struct mwAwareSnapshot *id); + + +/** Appropriate function type for the on-option signal. The option's +    value may need to be explicitly loaded in some instances, +    resulting in this handler being triggered again. + +    @param list    mwAwareList emiting the signal +    @param id      awareness the attribute belongs to +    @param attrib  attribute +*/ +typedef void (*mwAwareIdAttributeHandler) +     (struct mwAwareList *list, +      struct mwAwareIdBlock *id, +      struct mwAwareAttribute *attrib); + + +struct mwAwareListHandler { +  /** handle aware updates */ +  mwAwareSnapshotHandler on_aware; + +  /** handle attribute updates */ +  mwAwareIdAttributeHandler on_attrib; + +  /** optional. Called from mwAwareList_free */ +  void (*clear)(struct mwAwareList *list); +}; + + +struct mwServiceAware * +mwServiceAware_new(struct mwSession *session, +		   struct mwAwareHandler *handler); + + +/** Set an attribute value for this session */ +int mwServiceAware_setAttribute(struct mwServiceAware *srvc, +				guint32 key, struct mwOpaque *opaque); + + +int mwServiceAware_setAttributeBoolean(struct mwServiceAware *srvc, +				       guint32 key, gboolean val); + + +int mwServiceAware_setAttributeInteger(struct mwServiceAware *srvc, +				       guint32 key, guint32 val); + + +int mwServiceAware_setAttributeString(struct mwServiceAware *srvc, +				      guint32 key, const char *str); + + +/** Unset an attribute for this session */ +int mwServiceAware_unsetAttribute(struct mwServiceAware *srvc, +				  guint32 key); + + +guint32 mwAwareAttribute_getKey(const struct mwAwareAttribute *attrib); + + +gboolean mwAwareAttribute_asBoolean(const struct mwAwareAttribute *attrib); + + +guint32 mwAwareAttribute_asInteger(const struct mwAwareAttribute *attrib); + + +/** Copy of attribute string, must be g_free'd. If the attribute's +    content cannot be loaded as a string, returns NULL */ +char *mwAwareAttribute_asString(const struct mwAwareAttribute *attrib); + + +/** Direct access to an attribute's underlying opaque */ +const struct mwOpaque * +mwAwareAttribute_asOpaque(const struct mwAwareAttribute *attrib); + + +/** Allocate and initialize an aware list */ +struct mwAwareList * +mwAwareList_new(struct mwServiceAware *srvc, +		struct mwAwareListHandler *handler); + + +/** Clean and free an aware list */ +void mwAwareList_free(struct mwAwareList *list); + + +struct mwAwareListHandler *mwAwareList_getHandler(struct mwAwareList *list); + + +/// Miranda NG adaptation start - new method +struct mwServiceAware *mwAwareList_getServiceAware(struct mwAwareList *list); +/// Miranda NG adaptation end + + +/** Add a collection of user IDs to an aware list. +    @param list     mwAwareList to add user ID to +    @param id_list  mwAwareIdBlock list of user IDs to add +    @return         0 for success, non-zero to indicate an error. +*/ +int mwAwareList_addAware(struct mwAwareList *list, GList *id_list); + + +/** Remove a collection of user IDs from an aware list. +    @param list     mwAwareList to remove user ID from +    @param id_list  mwAwareIdBlock list of user IDs to remove +    @return  0      for success, non-zero to indicate an error. +*/ +int mwAwareList_removeAware(struct mwAwareList *list, GList *id_list); + + +int mwAwareList_removeAllAware(struct mwAwareList *list); + + +/** watch an NULL terminated array of keys */ +int mwAwareList_watchAttributeArray(struct mwAwareList *list, +				    guint32 *keys); + + +/** watch a NULL terminated list of keys */ +int mwAwareList_watchAttributes(struct mwAwareList *list, +				guint32 key, ...); + + +/** stop watching a NULL terminated array of keys */ +int mwAwareList_unwatchAttributeArray(struct mwAwareList *list, +				      guint32 *keys); + + +/** stop watching a NULL terminated list of keys */ +int mwAwareList_unwatchAttributes(struct mwAwareList *list, +				  guint32 key, ...); + + +/** remove all watched attributes */ +int mwAwareList_unwatchAllAttributes(struct mwAwareList *list); + + +guint32 *mwAwareList_getWatchedAttributes(struct mwAwareList *list); + + +void mwAwareList_setClientData(struct mwAwareList *list, +			       gpointer data, GDestroyNotify cleanup); + + +void mwAwareList_removeClientData(struct mwAwareList *list); + + +gpointer mwAwareList_getClientData(struct mwAwareList *list); + + +/** trigger a got_aware event constructed from the passed user and +    status information. Useful for adding false users and having the +    getText function work for them */ +void mwServiceAware_setStatus(struct mwServiceAware *srvc, +			      struct mwAwareIdBlock *user, +			      struct mwUserStatus *stat); + + +/** look up the status description for a user */ +const char *mwServiceAware_getText(struct mwServiceAware *srvc, +				   struct mwAwareIdBlock *user); + + +/** look up the last known copy of an attribute for a user by the +    attribute's key */ +const struct mwAwareAttribute * +mwServiceAware_getAttribute(struct mwServiceAware *srvc, +			    struct mwAwareIdBlock *user, +			    guint32 key); + + +/// Miranda NG adaptation start - new method +struct mwService *mwServiceAware_getService(struct mwServiceAware *srvc); +/// Miranda NG adaptation end + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_SRVC_AWARE_H */ + diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_conf.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_conf.h new file mode 100644 index 0000000000..1447fd3830 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_conf.h @@ -0,0 +1,216 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_SRVC_CONF_H +#define _MW_SRVC_CONF_H + + +#include <glib/glist.h> +#include "mw_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Type identifier for the conference service */ +#define mwService_CONFERENCE  0x80000010 + + +enum mwConferenceState { +  mwConference_NEW,      /**< new outgoing conference */ +  mwConference_PENDING,  /**< outgoing conference pending creation */ +  mwConference_INVITED,  /**< invited to incoming conference */ +  mwConference_OPEN,     /**< conference open and active */ +  mwConference_CLOSING,  /**< conference is closing */ +  mwConference_ERROR,    /**< conference is closing due to error */ +  mwConference_UNKNOWN,  /**< unable to determine conference state */ +}; + + +/** @struct mwServiceConference +    Instance of the multi-user conference service */ +struct mwServiceConference; + + +/** @struct mwConference +    A multi-user chat */ +struct mwConference; + + +/** Handler structure used to provide callbacks for an instance of the +    conferencing service */ +struct mwConferenceHandler { + +  /** 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 (*on_invited)(struct mwConference *conf, +		     struct mwLoginInfo *inviter, const char *invite); + +  /** 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 (*conf_opened)(struct mwConference *conf, GList *members); + +  /** triggered when a conference is closed. This is typically when +      we've left it */ +  void (*conf_closed)(struct mwConference *, guint32 reason); + +  /** triggered when someone joins the conference */ +  void (*on_peer_joined)(struct mwConference *, struct mwLoginInfo *); + +  /** triggered when someone leaves the conference */ +  void (*on_peer_parted)(struct mwConference *, struct mwLoginInfo *); + +  /** triggered when someone says something */ +  void (*on_text)(struct mwConference *conf, +		  struct mwLoginInfo *who, const char *what); + +  /** typing notification */ +  void (*on_typing)(struct mwConference *conf, +		    struct mwLoginInfo *who, gboolean typing); + +  /** optional. called from mwService_free */ +  void (*clear)(struct mwServiceConference *srvc); +}; + + +/** Allocate a new conferencing service, attaching the given handler +    @param sess     owning session +    @param handler  handler providing call-back functions for the service + */ +struct mwServiceConference * +mwServiceConference_new(struct mwSession *sess, +			struct mwConferenceHandler *handler); + + +/** @returns the conference handler for the service */ +struct mwConferenceHandler * +mwServiceConference_getHandler(struct mwServiceConference *srvc); + + +/** a mwConference list of the conferences in this service. The GList +    will need to be destroyed with g_list_free after use */ +GList *mwServiceConference_getConferences(struct mwServiceConference *srvc); + + +/** Allocate a new conference, in state NEW with the given title. +    @see mwConference_create */ +struct mwConference *mwConference_new(struct mwServiceConference *srvc, +				      const char *title); + + +/** @returns the owning service of a conference */ +/// Miranda NG adaptation start - renamed method +struct mwServiceConference *mwConference_getServiceConference(struct mwConference *conf); +/// Miranda NG adaptation end + + +/// Miranda NG adaptation start - new method +struct mwService *mwServiceConference_getService(struct mwServiceConference *srvc); +/// Miranda NG adaptation end + + +/** @returns unique conference name */ +const char *mwConference_getName(struct mwConference *conf); + + +/** @returns conference title */ +const char *mwConference_getTitle(struct mwConference *conf); + + +/** a mwIdBlock list of the members of the conference. The GList will +    need to be free'd after use */ +GList *mwConference_getMembers(struct mwConference *conf); + + +/** Initiate a conference. Conference must be in state NEW. If no name +    or title for the conference has been set, they will be +    generated. Conference will be placed into state PENDING. */ +int mwConference_open(struct mwConference *conf); + + +/** Leave and close an existing conference, or reject an invitation. +    Triggers mwServiceConfHandler::conf_closed and free's the +    conference. + */ +int mwConference_destroy(struct mwConference *conf, +			 guint32 reason, const char *text); + + +#define mwConference_reject(c,r,t) \ +  mwConference_destroy((c),(r),(t)) + + +/** accept a conference invitation. Conference must be in the state +    INVITED. */ +int mwConference_accept(struct mwConference *conf); + + +/** invite another user to an ACTIVE conference +    @param conf  conference +    @param who   user to invite +    @param text  invitation message + */ +int mwConference_invite(struct mwConference *conf, +			struct mwIdBlock *who, const char *text); + + +/** send a text message over an open conference */ +int mwConference_sendText(struct mwConference *conf, const char *text); + + +/** send typing notification over an open conference */ +int mwConference_sendTyping(struct mwConference *conf, gboolean typing); + + +/** associate arbitrary client data and an optional cleanup function +    with a conference. If there is already client data with a clear +    function, it will not be called. */ +void mwConference_setClientData(struct mwConference *conf, +				gpointer data, GDestroyNotify clear); + + +/** reference associated client data */ +gpointer mwConference_getClientData(struct mwConference *conf); + + +/** remove associated client data if any, and call the cleanup +    function on the data as necessary */ +void mwConference_removeClientData(struct mwConference *conf); + + +#ifdef __cplusplus +} +#endif +				     + +#endif /* _MW_SRVC_CONF_H */ + diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_dir.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_dir.h new file mode 100644 index 0000000000..b9230bbf08 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_dir.h @@ -0,0 +1,212 @@ +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_SRVC_DIR_H +#define _MW_SERV_DIR_H + + +#include <glib.h> +#include <glib/glist.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +struct mwSession; + + +#define SERVICE_DIRECTORY  0x0000001a + + +/** @struct mwServiceDirectory + +    the directory service. */ +struct mwServiceDirectory; + + +/** @struct mwAddressBook + +    server-side collection of users and groups. Open a directory +    based on an address book to search or list its contents */ +struct mwAddressBook; + + +/** @struct mwDirectory + +    searchable directory, based off of an address book */ +struct mwDirectory; + + +enum mwDirectoryState { +  mwDirectory_NEW,      /**< directory is created, but not open */ +  mwDirectory_PENDING,  /**< directory has in the process of opening */ +  mwDirectory_OPEN,     /**< directory is open */ +  mwDirectory_ERROR,    /**< error opening or using directory */ +  mwDirectory_UNKNOWN,  /**< error determining directory state */ +}; + + +/** return value of directory searches that fail */ +#define DIR_SEARCH_ERROR  0x00000000 + + +#define MW_DIRECTORY_IS_STATE(dir, state) \ +  (mwDirectory_getState(dir) == (state)) + +#define MW_DIRECTORY_IS_NEW(dir) \ +  MW_DIRECTORY_IS_STATE((dir), mwDirectory_NEW) + +#define MW_DIRECTORY_IS_PENDING(dir) \ +  MW_DIRECTORY_IS_STATE((dir), mwDirectory_PENDING) + +#define MW_DIRECTORY_IS_OPEN(dir) \ +  MW_DIRECTORY_IS_STATE((dir), mwDirectory_OPEN) + + +enum mwDirectoryMemberType { +  mwDirectoryMember_USER   = 0x0000, +  mwDirectoryMember_GROUP  = 0x0001, +}; + + +struct mwDirectoryMember { +  guint16 type;      /**< @see mwDirectoryMemberType */ +  char *id;          /**< proper ID for member */ +  char *long_name;   /**< full name of member (USER type only) */ +  char *short_name;  /**< short name of member */ +  guint16 foo;       /**< unknown */ +}; + + +/** Appropriate function signature for handling directory search results */ +typedef void (*mwSearchHandler) +     (struct mwDirectory *dir, +      guint32 code, guint32 offset, GList *members); + + +/** handles asynchronous events for a directory service instance */ +struct mwDirectoryHandler { + +  /** handle receipt of the address book list from the service. +      Initially triggered by mwServiceDirectory_refreshAddressBooks +      and at service startup */ +  void (*on_book_list)(struct mwServiceDirectory *srvc, GList *books); + +  /** triggered when a directory has been successfully opened */ +  void (*dir_opened)(struct mwDirectory *dir); + +  /** triggered when a directory has been closed */ +  void (*dir_closed)(struct mwDirectory *dir, guint32 reason); + +  /** optional. called from mwService_free */ +  void (*clear)(struct mwServiceDirectory *srvc); +}; + + +/** Allocate a new directory service instance for use with session */ +struct mwServiceDirectory * +mwServiceDirectory_new(struct mwSession *session, +		       struct mwDirectoryHandler *handler); + + +/** the handler associated with the service at its creation */ +struct mwDirectoryHandler * +mwServiceDirectory_getHandler(struct mwServiceDirectory *srvc); + + +/** most recent list of address books available in service */ +GList *mwServiceDirectory_getAddressBooks(struct mwServiceDirectory *srvc); + + +/** submit a request to obtain an updated list of address books from +    service */ +int mwServiceDirectory_refreshAddressBooks(struct mwServiceDirectory *srvc); + + +/** list of directories in the service */ +GList *mwServiceDirectory_getDirectories(struct mwServiceDirectory *srvc); + + +/** list of directories associated with address book. Note that the +    returned GList will need to be free'd after use */ +GList *mwAddressBook_getDirectories(struct mwAddressBook *book); + + +/** the name of the address book */ +const char *mwAddressBook_getName(struct mwAddressBook *book); + + +/** allocate a new directory based off the given address book */ +struct mwDirectory *mwDirectory_new(struct mwAddressBook *book); + + +enum mwDirectoryState mwDirectory_getState(struct mwDirectory *dir); + + +/** set client data. If there is an existing clear function, it will +    not be called */ +void mwDirectory_setClientData(struct mwDirectory *dir, +			       gpointer data, GDestroyNotify clear); + + +/** reference associated client data */ +gpointer mwDirectory_getClientData(struct mwDirectory *dir); + + +/** remove and cleanup user data */ +void mwDirectory_removeClientData(struct mwDirectory *dir); + + +/** reference owning service */ +struct mwServiceDirectory *mwDirectory_getService(struct mwDirectory *dir); + + +/** reference owning address book */ +struct mwAddressBook *mwDirectory_getAddressBook(struct mwDirectory *dir); + + +/** initialize a directory. */ +int mwDirectory_open(struct mwDirectory *dir, mwSearchHandler cb); + + +/** continue a search into its next results */ +int mwDirectory_next(struct mwDirectory *dir); + + +/** continue a search into its previous results */ +int mwDirectory_previous(struct mwDirectory *dir); + + +/** initiate a search on an open directory */ +int mwDirectory_search(struct mwDirectory *dir, const char *query); + + +/** close and free the directory, and unassociate it with its owning +    address book and service */ +int mwDirectory_destroy(struct mwDirectory *dir); + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_SRVC_DIR_H */ diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_ft.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_ft.h new file mode 100644 index 0000000000..aef7de886a --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_ft.h @@ -0,0 +1,255 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + + +#ifndef _MW_SRVC_FT_H +#define _MW_SRVC_FT_H + + +/** @file mw_srvc_ft.h + +    A file transfer is a simple way to get large chunks of binary data +    from one client to another. +*/ + + +#include "mw_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** @struct mwServiceFileTransfer +    File transfer service +*/ +struct mwServiceFileTransfer; + + +/** @struct mwFileTransfer +    A single file trasfer session + */ +struct mwFileTransfer; + + +#define mwService_FILE_TRANSFER  0x00000038 + + +enum mwFileTransferState { +  mwFileTransfer_NEW,   /**< file transfer is not open */ +  mwFileTransfer_PENDING,  /**< file transfer is opening */ +  mwFileTransfer_OPEN,     /**< file transfer is open */ +  mwFileTransfer_CANCEL_LOCAL, +  mwFileTransfer_CANCEL_REMOTE, +  mwFileTransfer_DONE, +  mwFileTransfer_ERROR,    /**< error in file transfer */ +  mwFileTransfer_UNKNOWN,  /**< unknown state */ +}; + + +#define mwFileTransfer_isState(ft, state) \ +  (mwFileTransfer_getState(ft) == (state)) + +#define mwFileTransfer_isNew(ft) \ +  mwFileTransfer_isState((ft), mwFileTransfer_NEW) + +#define mwFileTransfer_isPending(ft) \ +  mwFileTransfer_isState((ft), mwFileTransfer_PENDING) + +#define mwFileTransfer_isOpen(ft) \ +  mwFileTransfer_isState((ft), mwFileTransfer_OPEN) + +#define mwFileTransfer_isDone(ft) \ +  mwFileTransfer_isState((ft), mwFileTransfer_DONE) + +#define mwFileTransfer_isCancelLocal(ft) \ +  mwFileTransfer_isState((ft), mwFileTransfer_CANCEL_LOCAL) + +#define mwFileTransfer_isCancelRemote(ft) \ +  mwFileTransfer_isState((ft), mwFileTransfer_CANCEL_REMOTE) + + +enum mwFileTranferCode { +  mwFileTransfer_SUCCESS   = 0x00000000, +  mwFileTransfer_REJECTED  = 0x08000606, +}; + + +struct mwFileTransferHandler { + +  /** an incoming file transfer has been offered */ +  void (*ft_offered)(struct mwFileTransfer *ft); + +  /** a file transfer has been fully initiated */ +  void (*ft_opened)(struct mwFileTransfer *ft); + +  /** 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 (*ft_closed)(struct mwFileTransfer *ft, guint32 code); + +  /** receive a chunk of a file from an inbound file transfer. */ +  void (*ft_recv)(struct mwFileTransfer *ft, struct mwOpaque *data); + +  /** 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 (*ft_ack)(struct mwFileTransfer *ft); + +  /** optional. called from mwService_free */ +  void (*clear)(struct mwServiceFileTransfer *srvc); +}; + + +struct mwServiceFileTransfer * +mwServiceFileTransfer_new(struct mwSession *session, +			  struct mwFileTransferHandler *handler); + + +struct mwFileTransferHandler * +mwServiceFileTransfer_getHandler(struct mwServiceFileTransfer *srvc); + + +const GList * +mwServiceFileTransfer_getTransfers(struct mwServiceFileTransfer *srvc); + + +/// Miranda NG adaptation start - new method +struct mwService * +mwServiceFileTransfer_getService(struct mwServiceFileTransfer *srvc); +/// Miranda NG adaptation end + + +struct mwFileTransfer * +mwFileTransfer_new(struct mwServiceFileTransfer *srvc, +		   const struct mwIdBlock *who, const char *msg, +		   const char *filename, guint32 filesize); + + +/** deallocate a file transfer. will call mwFileTransfer_close if +    necessary */ +void +mwFileTransfer_free(struct mwFileTransfer *ft); + + +/** the status of this file transfer */ +enum mwFileTransferState +mwFileTransfer_getState(struct mwFileTransfer *ft); + + +struct mwServiceFileTransfer * +mwFileTransfer_getService(struct mwFileTransfer *ft); + + +/** the user on the other end of the file transfer */ +const struct mwIdBlock * +mwFileTransfer_getUser(struct mwFileTransfer *ft); + + +/** the message sent along with an offered file transfer */ +const char * +mwFileTransfer_getMessage(struct mwFileTransfer *ft); + + +/** the publicized file name. Not necessarily related to any actual +    file on either system */ +const char * +mwFileTransfer_getFileName(struct mwFileTransfer *ft); + + +/** total bytes intended to be sent/received */ +guint32 mwFileTransfer_getFileSize(struct mwFileTransfer *ft); + + +/** bytes remaining to be received/send */ +guint32 mwFileTransfer_getRemaining(struct mwFileTransfer *ft); + + +/** count of bytes sent/received over this file transfer so far */ +#define mwFileTransfer_getSent(ft) \ +  (mwFileTransfer_getFileSize(ft) - mwFileTransfer_getRemaining(ft)) + + +/** initiate an outgoing file transfer */ +int mwFileTransfer_offer(struct mwFileTransfer *ft); + + +/** accept an incoming file transfer */ +int mwFileTransfer_accept(struct mwFileTransfer *ft); + + +/** reject an incoming file transfer */ +#define mwFileTransfer_reject(ft) \ +  mwFileTransfer_close((ft), mwFileTransfer_REJECTED) + + +/** cancel an open file transfer */ +#define mwFileTransfer_cancel(ft) \ +  mwFileTransfer_close((ft), mwFileTransfer_SUCCESS); + + +/** Close a file transfer. This will trigger the ft_close function of the +    session's handler. + +    @see mwFileTransfer_reject +    @see mwFileTransfer_cancel +*/ +int mwFileTransfer_close(struct mwFileTransfer *ft, guint32 code); + + +/** send a chunk of data over an outbound file transfer. The client at +    the other end of the transfer should respond with an acknowledgement +    message, which can be caught in the service's handler. + +    @see mwFileTransferHandler::ft_ack +*/ +int mwFileTransfer_send(struct mwFileTransfer *ft, +			struct mwOpaque *data); + + +/** acknowledge the receipt of a chunk of data from an inbound file +    transfer.  This should be done after every received chunk, or the +    transfer will stall. However, not all clients will wait for an ack +    after sending a chunk before sending the next chunk, so it is +    possible to have the handler's ft_recv function triggered again +    even if no ack was sent. + +    @see mwFileTransferHandler::ft_recv +*/ +int mwFileTransfer_ack(struct mwFileTransfer *ft); + + +void mwFileTransfer_setClientData(struct mwFileTransfer *ft, +				  gpointer data, GDestroyNotify clean); + + +gpointer mwFileTransfer_getClientData(struct mwFileTransfer *ft); + + +void mwFileTransfer_removeClientData(struct mwFileTransfer *ft); + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_SRVC_FT_H */ diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_im.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_im.h new file mode 100644 index 0000000000..adb710e32c --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_im.h @@ -0,0 +1,281 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_SRVC_IM_H +#define _MW_SRVC_IM_H + + +/** @file mw_srvc_im.h + +    The IM service provides one-on-one communication between +    users. Messages sent over conversations may relay different types +    of information, in a variety of formats. The basic feature-set +    provides plain-text chat with typing notification. More complex +    features may be negotiated transparently by setting the IM Client +    Type for a conversation, or for the service as a whole. +*/ + + +#include <glib.h> +#include "mw_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif +   +   +/* identifier for the IM service */ +#define mwService_IM  0x00001000 +   +   +/** @struct mwServiceIm + +    An instance of the IM service. This service provides simple +    instant messaging functionality */ +struct mwServiceIm; + + +/** @struct mwConversation + +    A conversation between the local service and a single other user */ +struct mwConversation; + + +enum mwImClientType { +  mwImClient_PLAIN       = 0x00000001,  /**< text, typing */ +  mwImClient_NOTESBUDDY  = 0x00033453,  /**< adds html, subject, mime */ +  mwImClient_PRECONF     = 0x00000019,  /**< pre-conference, legacy */ +  mwImClient_UNKNOWN     = 0xffffffff,  /**< trouble determining type */ +}; + + +/** +   Types of supported messages. When a conversation is created, the +   least common denominator of features between either side of the +   conversation (based on what features are available in the IM +   service itself) becomes the set of supported features for that +   conversation. At any point, the feature set for the service may +   change, without affecting any existing conversations. + +   @see mwServiceIm_supports +   @see mwServiceIm_setSupported +   @see mwConversation_supports +   @see mwConversation_send +   @see mwServiceImHandler::conversation_recv + */ +enum mwImSendType { +  mwImSend_PLAIN,   /**< char *, plain-text message */ +  mwImSend_TYPING,  /**< gboolean, typing status */ +  mwImSend_HTML,    /**< char *, HTML formatted message (NOTESBUDDY) */ +  mwImSend_SUBJECT, /**< char *, conversation subject (NOTESBUDDY) */ +  mwImSend_MIME,    /**< char *, MIME-encoded message (NOTESBUDDY) */ +  mwImSend_TIMESTAMP, /**< char *, YYYY:MM:DD:HH:mm:SS format (NOTESBUDDY) */ +}; + + + +/** @see mwConversation_getState */ +enum mwConversationState { +  mwConversation_CLOSED,   /**< conversation is not open */ +  mwConversation_PENDING,  /**< conversation is opening */ +  mwConversation_OPEN,     /**< conversation is open */ +  mwConversation_UNKNOWN,  /**< unknown state */ +}; + + +#define mwConversation_isState(conv, state) \ +  (mwConversation_getState(conv) == (state)) + +#define mwConversation_isClosed(conv) \ +  mwConversation_isState((conv), mwConversation_CLOSED) + +#define mwConversation_isPending(conv) \ +  mwConversation_isState((conv), mwConversation_PENDING) + +#define mwConversation_isOpen(conv) \ +  mwConversation_isState((conv), mwConversation_OPEN) + + + +/** IM Service Handler. Provides functions for events triggered from an +    IM service instance. */ +struct mwImHandler { + +  /** A conversation has been successfully opened */ +  void (*conversation_opened)(struct mwConversation *conv); + +  /** A conversation has been closed */ +  void (*conversation_closed)(struct mwConversation *conv, guint32 err); +   +  /** A message has been received on a conversation */ +  void (*conversation_recv)(struct mwConversation *conv, +			    enum mwImSendType type, gconstpointer msg); + +  /** Handle a Place invitation. Set this to NULL and we should end up +      receiving a conference invitation instead. */ +  void (*place_invite)(struct mwConversation *conv, +		       const char *message, +		       const char *title, const char *name); + +  /** optional. called from mwService_free */ +  void (*clear)(struct mwServiceIm *srvc); +}; + + +struct mwServiceIm *mwServiceIm_new(struct mwSession *session, +				    struct mwImHandler *handler); + + +struct mwImHandler *mwServiceIm_getHandler(struct mwServiceIm *srvc); + + +/// Miranda NG adaptation start - new method +struct mwService *mwServiceIm_getService(struct mwServiceIm *srvc); +/// Miranda NG adaptation end + + +/** reference an existing conversation to target, or create a new +    conversation to target if one does not already exist */ +struct mwConversation *mwServiceIm_getConversation(struct mwServiceIm *srvc, +						   struct mwIdBlock *target); + + +/** reference an existing conversation to target */ +struct mwConversation *mwServiceIm_findConversation(struct mwServiceIm *srvc, +						    struct mwIdBlock *target); + + +/** determine if the conversations created from this service will +    support a given send type */ +gboolean mwServiceIm_supports(struct mwServiceIm *srvc, +			      enum mwImSendType type); + + +/** Set the default client type for the service. Newly created +    conversations will attempt to meet this level of functionality +    first. + +    @param srvc       the IM service +    @param type       the send type to enable/disable +*/ +void mwServiceIm_setClientType(struct mwServiceIm *srvc, +			       enum mwImClientType type); + + +enum mwImClientType mwServiceIm_getClientType(struct mwServiceIm *srvc); + + +/** attempt to open a conversation. If the conversation was not +    already open and it is accepted, +    mwServiceImHandler::conversation_opened will be triggered. Upon +    failure, mwServiceImHandler::conversation_closed will be +    triggered */ +void mwConversation_open(struct mwConversation *conv); + + +/** close a conversation. If the conversation was not already closed, +    mwServiceImHandler::conversation_closed will be triggered */ +void mwConversation_close(struct mwConversation *conv, guint32 err); + + +/** determine whether a conversation supports the given message type */ +gboolean mwConversation_supports(struct mwConversation *conv, +				 enum mwImSendType type); + + +enum mwImClientType mwConversation_getClientType(struct mwConversation *conv); + + +/** get the state of a conversation + +    @see mwConversation_isOpen +    @see mwConversation_isClosed +    @see mwConversation_isPending +*/ +enum mwConversationState mwConversation_getState(struct mwConversation *conv); + + +/** send a message over an open conversation */ +int mwConversation_send(struct mwConversation *conv, +			enum mwImSendType type, gconstpointer send); + + +/** @returns owning service for a conversation */ +struct mwServiceIm *mwConversation_getService(struct mwConversation *conv); + + +/** login information for conversation partner. returns NULL if conversation  +    is not OPEN */ +struct mwLoginInfo *mwConversation_getTargetInfo(struct mwConversation *conv); + + +/** ID for conversation partner */ +struct mwIdBlock *mwConversation_getTarget(struct mwConversation *conv); + + +/** set whether outgoing messages should be encrypted using the +    negotiated cipher, if any */ +void mwConversation_setEncrypted(struct mwConversation *conv, +				 gboolean useCipher); + + +/** determine whether outgoing messages are being encrypted */ +gboolean mwConversation_isEncrypted(struct mwConversation *conv); + + +/** Associates client data with a conversation. If there is existing data, +    it will not have its cleanup function called. + +    @see mwConversation_getClientData +    @see mwConversation_removeClientData +*/ +void mwConversation_setClientData(struct mwConversation *conv, +				  gpointer data, GDestroyNotify clean); + + +/** Reference associated client data + +    @see mwConversation_setClientData +    @see mwConversation_removeClientData + */ +gpointer mwConversation_getClientData(struct mwConversation *conv); + + +/** Remove any associated client data, calling the optional cleanup +    function if one was provided + +    @see mwConversation_setClientData +    @see mwConversation_getClientData +*/ +void mwConversation_removeClientData(struct mwConversation *conv); + + +/** close and destroy the conversation and its backing channel, and +    call the optional client data cleanup function */ +void mwConversation_free(struct mwConversation *conv); + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_SRVC_IM_H */ diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_place.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_place.h new file mode 100644 index 0000000000..e17aa711c5 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_place.h @@ -0,0 +1,148 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_SRVC_PLACE_H +#define _MW_SRVC_PLACE_H + + +#include <glib/glist.h> +#include "mw_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Type identifier for the place service */ +#define mwService_PLACE  0x80000022 + + +/** @struct mwServicePlace */ +struct mwServicePlace; + + +/** @struct mwPlace */ +struct mwPlace; + + +struct mwPlaceHandler { +  void (*opened)(struct mwPlace *place); +  void (*closed)(struct mwPlace *place, guint32 code); + +  void (*peerJoined)(struct mwPlace *place, +		     const struct mwIdBlock *peer); + +  void (*peerParted)(struct mwPlace *place, +		     const struct mwIdBlock *peer); + +  void (*peerSetAttribute)(struct mwPlace *place, +			   const struct mwIdBlock *peer, +			   guint32 attr, struct mwOpaque *o); + +  void (*peerUnsetAttribute)(struct mwPlace *place, +			     const struct mwIdBlock *peer, +			     guint32 attr); + +  void (*message)(struct mwPlace *place, +		  const struct mwIdBlock *who, +		  const char *msg); + +  void (*clear)(struct mwServicePlace *srvc); +}; + + +enum mwPlacePeerAttribute { +  mwPlacePeer_TYPING = 0x00000008, +}; + + +struct mwServicePlace * +mwServicePlace_new(struct mwSession *session, +		   struct mwPlaceHandler *handler); + + +struct mwPlaceHandler * +mwServicePlace_getHandler(struct mwServicePlace *srvc); + + +const GList *mwServicePlace_getPlaces(struct mwServicePlace *srvc); + + +struct mwPlace *mwPlace_new(struct mwServicePlace *srvc, +			    const char *name, const char *title); + + +struct mwServicePlace *mwPlace_getService(struct mwPlace *place); + + +const char *mwPlace_getName(struct mwPlace *place); + + +const char *mwPlace_getTitle(struct mwPlace *place); + + +int mwPlace_open(struct mwPlace *place); + + +int mwPlace_destroy(struct mwPlace *place, guint32 code); + + +/** returns a GList* of struct mwIdBlock*. The GList will need to be +    freed after use, the mwIdBlock structures should not be modified +    or freed */ +GList *mwPlace_getMembers(struct mwPlace *place); + + +int mwPlace_sendText(struct mwPlace *place, const char *msg); + + +/** send a legacy invitation for this place to a user. The user will +    receive an apparent invitation from a Conference (rather than a +    Place) */ +int mwPlace_legacyInvite(struct mwPlace *place, +			 struct mwIdBlock *idb, +			 const char *message); + + +int mwPlace_setAttribute(struct mwPlace *place, guint32 attrib, +			 struct mwOpaque *data); + + +int mwPlace_unsetAttribute(struct mwPlace *place, guint32 attrib); + + +void mwPlace_setClientData(struct mwPlace *place, +			   gpointer data, GDestroyNotify clean); + + +gpointer mwPlace_getClientData(struct mwPlace *place); + + +void mwPlace_removeClientData(struct mwPlace *place); + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_SRVC_PLACE_H */ + diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_resolve.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_resolve.h new file mode 100644 index 0000000000..436b20a5d5 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_resolve.h @@ -0,0 +1,155 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_SRVC_RESOLVE_H +#define _MW_SRVC_RESOLVE_H + + +#include <glib.h> +#include <glib/glist.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Type identifier for the conference service */ +#define mwService_RESOLVE  0x00000015 + + +/** Return value of mwServiceResolve_search indicating an error */ +#define SEARCH_ERROR  0x00 + + +/** @struct mwServiceResolve +    User lookup service */ +struct mwServiceResolve; + + +enum mwResolveFlag { +  /** return unique results or none at all */ +  mwResolveFlag_UNIQUE    = 0x00000001, + +  /** return only the first result */ +  mwResolveFlag_FIRST     = 0x00000002, + +  /** search all directories, not just the first with a match */ +  mwResolveFlag_ALL_DIRS  = 0x00000004, + +  /** search for users */ +  mwResolveFlag_USERS     = 0x00000008, + +  /** search for groups */ +  mwResolveFlag_GROUPS    = 0x00000010, +}; + + +/** @see mwResolveResult */ +enum mwResolveCode { +  /** successful search */ +  mwResolveCode_SUCCESS     = 0x00000000, + +  /** only some of the nested searches were successful */ +  mwResolveCode_PARTIAL     = 0x00010000, + +  /** more than one result (occurs when mwResolveFlag_UNIQUE is used +      and more than one result would have been otherwise returned) */ +  mwResolveCode_MULTIPLE    = 0x80020000, + +  /** the name is not resolvable due to its format */ +  mwResolveCode_BAD_FORMAT  = 0x80030000, +}; + + +enum mwResolveMatchType { +  mwResolveMatch_USER   = 0x00000001, +  mwResolveMatch_GROUP  = 0x00000002, +}; + + +struct mwResolveMatch { +  char *id;      /**< user id */ +  char *name;    /**< user name */ +  char *desc;    /**< description */ +  guint32 type;  /**< @see mwResolveMatchType */ +}; + + +struct mwResolveResult { +  guint32 code;    /**< @see mwResolveCode */ +  char *name;      /**< name of the result */ +  GList *matches;  /**< list of mwResolveMatch */ +}; + + +/** Handle the results of a resolve request. If there was a cleanup +    function specified to mwServiceResolve_search, it will be called +    upon the user data after this callback returns. + +    @param srvc     the resolve service +    @param id       the resolve request ID +    @param code     return code +    @param results  list of mwResolveResult +    @param data     optional user data attached to the request +*/ +typedef void (*mwResolveHandler) +     (struct mwServiceResolve *srvc, +      guint32 id, guint32 code, GList *results, +      gpointer data); + + +/** Allocate a new resolve service */ +struct mwServiceResolve *mwServiceResolve_new(struct mwSession *); + + +/** Inisitate a resolve request. + +    @param srvc     the resolve service +    @param queries  list query strings +    @param flags    search flags +    @param handler  result handling function +    @param data     optional user data attached to the request +    @param cleanup  optional function to clean up user data +    @return         generated ID for the search request, or SEARCH_ERROR +*/ +guint32 mwServiceResolve_resolve(struct mwServiceResolve *srvc, +				 GList *queries, enum mwResolveFlag flags, +				 mwResolveHandler handler, +				 gpointer data, GDestroyNotify cleanup); + + +/** Cancel a resolve request by its generated ID. The handler function +    will not be called, and the optional cleanup function will be +    called upon the optional user data for the request */ +void mwServiceResolve_cancelResolve(struct mwServiceResolve *, guint32); + + +/// Miranda NG adaptation start - new method +struct mwService *mwServiceResolve_getService(struct mwServiceResolve *srvc); +/// Miranda NG adaptation end + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_SRVC_RESOLVE_H */ diff --git a/protocols/Sametime/src/meanwhile/src/mw_srvc_store.h b/protocols/Sametime/src/meanwhile/src/mw_srvc_store.h new file mode 100644 index 0000000000..b55ddf21fe --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_srvc_store.h @@ -0,0 +1,201 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_SRVC_STORE_H +#define _MW_SRVC_STORE_H + + +#include <glib.h> +#include "mw_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Type identifier for the storage service */ +#define mwService_STORAGE  0x00000018 + + +/** @struct mwServiceStorage +    @see mwServiceStorage_new + +    Instance of the storage service */ +struct mwServiceStorage; + + +/** @struct mwStorage + +    Unit Represents information intended for loading from or saving to +    the storage service */ +struct mwStorageUnit; + + +/** The upper limit of reserved Lotus keys */ +#define LOTUS_RESERVED_LIMIT  0x186a0 + + +/** Check if a key is in the range of Lotus reserved keys */ +#define KEY_IS_LOTUS_RESERVED(key) \ +  (((guint32) key) <= (LOTUS_RESERVED_LIMIT)) + + +/** Some common keys storage keys. Anything in the range 0x00 to +    0x186a0 (100000) is reserved for use by the Lotus +    clients. */ +enum mwStorageKey { + +  /** The buddy list, in the Sametime .dat file format. String */ +  mwStore_AWARE_LIST      = 0x00000000, + +  /** Default text for chat invitations. String */ +  mwStore_INVITE_CHAT     = 0x00000006, + +  /** Default text for meeting invitations. String */ +  mwStore_INVITE_MEETING  = 0x0000000e, + +  /** Last five Away messages, separated by semicolon. String */ +  mwStore_AWAY_MESSAGES   = 0x00000050, + +  /** Last five Busy (DND) messages, separated by semicolon. String */ +  mwStore_BUSY_MESSAGES   = 0x0000005a, + +  /** Last five Active messages, separated by semicolon. String */ +  mwStore_ACTIVE_MESSAGES = 0x00000064, +}; + + +/** Appropriate function type for load and store callbacks. +    @param srvc       the storage service +    @param result     the result value of the load or store call +    @param item       the storage unit loaded or saved +    @param data       optional user data +*/ +typedef void (*mwStorageCallback) +     (struct mwServiceStorage *srvc, +      guint32 result, struct mwStorageUnit *item, +      gpointer data); + + +/** Allocates and initializes a storage service instance for use on +    the passed session. */ +struct mwServiceStorage *mwServiceStorage_new(struct mwSession *); + + +/** create an empty storage unit */ +struct mwStorageUnit *mwStorageUnit_new(guint32 key); + + +/** creates a storage unit with the passed key, and a copy of data. */ +struct mwStorageUnit *mwStorageUnit_newOpaque(guint32 key, +					      struct mwOpaque *data); + + +/** creates a storage unit with the passed key, and an encapsulated +    boolean value */ +struct mwStorageUnit *mwStorageUnit_newBoolean(guint32 key, +					       gboolean val); + + +struct mwStorageUnit *mwStorageUnit_newInteger(guint32 key, +					       guint32 val); + + +/** creates a storage unit with the passed key, and an encapsulated +    string value. */ +struct mwStorageUnit *mwStorageUnit_newString(guint32 key, +					      const char *str); + + +/** get the key for the given storage unit */ +guint32 mwStorageUnit_getKey(struct mwStorageUnit *); + + +/** attempts to obtain a boolean value from a storage unit. If the +    unit is empty, or does not contain the type in a recongnizable +    format, val is returned instead */ +gboolean mwStorageUnit_asBoolean(struct mwStorageUnit *, gboolean val); + + +/** attempts to obtain a guint32 value from a storage unit. If the +    unit is empty, or does not contain the type in a recognizable +    format, val is returned instead */ +guint32 mwStorageUnit_asInteger(struct mwStorageUnit *, guint32 val); + + +/** attempts to obtain a string value from a storage unit. If the unit +    is empty, or does not contain the type in a recognizable format, +    NULL is returned instead. Note that the string returned is a copy, +    and will need to be deallocated at some point. */ +char *mwStorageUnit_asString(struct mwStorageUnit *); + + +/** direct access to the opaque data backing the storage unit */ +struct mwOpaque *mwStorageUnit_asOpaque(struct mwStorageUnit *); + + +/** clears and frees a storage unit */ +void mwStorageUnit_free(struct mwStorageUnit *); + +       +/** Initiates a load call to the storage service. If the service is +    not currently available, the call will be cached and processed +    when the service is started. + +    @param srvc       the storage service +    @param item       storage unit to load +    @param cb         callback function when the load call completes +    @param data       user data for callback +    @param data_free  optional cleanup function for user data +*/ +void mwServiceStorage_load(struct mwServiceStorage *srvc, +			   struct mwStorageUnit *item, +			   mwStorageCallback cb, +			   gpointer data, GDestroyNotify data_free); + + +/** Initiates a store call to the storage service. If the service is +    not currently available, the call will be cached and processed +    when the service is started. + +    @param srvc       the storage service +    @param item       storage unit to save +    @param cb         callback function when the load call completes +    @param data       optional user data for callback +    @param data_free  optional cleanup function for user data + */ +void mwServiceStorage_save(struct mwServiceStorage *srvc, +			   struct mwStorageUnit *item, +			   mwStorageCallback cb, +			   gpointer data, GDestroyNotify data_free); + + +/// Miranda NG adaptation start - new method +struct mwService *mwServiceStorage_getService(struct mwServiceStorage *srvc); +/// Miranda NG adaptation end + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_SRVC_STORE_H */ diff --git a/protocols/Sametime/src/meanwhile/src/mw_st_list.h b/protocols/Sametime/src/meanwhile/src/mw_st_list.h new file mode 100644 index 0000000000..39e1cbf84b --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_st_list.h @@ -0,0 +1,218 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_ST_LIST_H +#define _MW_ST_LIST_H + + +/** @file mw_st_list.h + +    Parse and compose buddy lists in the format commonly used by Sametime +    Connect clients. +*/ + + +#include <glib.h> +#include <glib/glist.h> +#include "mw_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ST_LIST_MAJOR  3 +#define ST_LIST_MINOR  1 +#define ST_LIST_MICRO  3 + + +enum mwSametimeGroupType { +  mwSametimeGroup_NORMAL  = 1,  /**< a normal group of users */ +  mwSametimeGroup_DYNAMIC = 2,  /**< a server-side group */ +  mwSametimeGroup_UNKNOWN = 0,  /**< error determining group type */ +}; + + +enum mwSametimeUserType { +  mwSametimeUser_NORMAL   = 1,  /**< user on same community */ +  mwSametimeUser_EXTERNAL = 2,  /**< external user */ +  mwSametimeUser_UNKNOWN  = 0,  /**< error determining user type */ +}; + + +/** @struct mwSametimeList + +    Represents a group-based buddy list. */ +struct mwSametimeList; + + +/** @struct mwSametimeGroup + +    Represents a group in a buddy list */ +struct mwSametimeGroup; + + +/** @struct mwSametimeUser + +    Represents a user in a group in a buddy list */ +struct mwSametimeUser; + + +/** Create a new list */ +struct mwSametimeList *mwSametimeList_new(); + + +/** Free the list, all of its groups, and all of the groups' members */ +void mwSametimeList_free(struct mwSametimeList *l); + + +/** Load a sametime list from a buffer. The list must be encapsulated +    as a string (eg, the first two bytes in the buffer should be the +    length of the string) */ +void mwSametimeList_get(struct mwGetBuffer *b, struct mwSametimeList *l); + + +/** Write a sametime list onto a buffer. The list will be encapsulated +    in a string (the first two bytes written will be the length of the +    rest of the written list data) */ +void mwSametimeList_put(struct mwPutBuffer *b, struct mwSametimeList *l); + + +/** convert a plain string into a sametime list */ +struct mwSametimeList *mwSametimeList_load(const char *str); + + +/** convert a sametime list into a string */ +char *mwSametimeList_store(struct mwSametimeList *l); + + +void mwSametimeList_setMajor(struct mwSametimeList *l, guint v); + + +guint mwSametimeList_getMajor(struct mwSametimeList *l); + + +void mwSametimeList_setMinor(struct mwSametimeList *l, guint v); + + +guint mwSametimeList_getMinor(struct mwSametimeList *l); + + +void mwSametimeList_setMicro(struct mwSametimeList *l, guint v); + + +guint mwSametimeList_getMicro(struct mwSametimeList *l); + + +/** Get a GList snapshot of the groups in a list */ +GList *mwSametimeList_getGroups(struct mwSametimeList *l); + + +struct mwSametimeGroup * +mwSametimeList_findGroup(struct mwSametimeList *l, +			 const char *name); + + +/** Create a new group in a list */ +struct mwSametimeGroup * +mwSametimeGroup_new(struct mwSametimeList *l, +		    enum mwSametimeGroupType type, +		    const char *name); + + +/** Remove a group from its list, and free it. Also frees all users +    contained in the group */ +void mwSametimeGroup_free(struct mwSametimeGroup *g); + + +enum mwSametimeGroupType mwSametimeGroup_getType(struct mwSametimeGroup *g); + + +const char *mwSametimeGroup_getName(struct mwSametimeGroup *g); + + +void mwSametimeGroup_setAlias(struct mwSametimeGroup *g, +			      const char *alias); + + +const char *mwSametimeGroup_getAlias(struct mwSametimeGroup *g); + + +void mwSametimeGroup_setOpen(struct mwSametimeGroup *g, gboolean open); + + +gboolean mwSametimeGroup_isOpen(struct mwSametimeGroup *g); + + +struct mwSametimeList *mwSametimeGroup_getList(struct mwSametimeGroup *g); + + +/** Get a GList snapshot of the users in a list */ +GList *mwSametimeGroup_getUsers(struct mwSametimeGroup *g); + + +struct mwSametimeUser * +mwSametimeGroup_findUser(struct mwSametimeGroup *g, +			 struct mwIdBlock *user); + + +/** Create a user in a group */ +struct mwSametimeUser * +mwSametimeUser_new(struct mwSametimeGroup *g, +		   enum mwSametimeUserType type, +		   struct mwIdBlock *user); + + +/** Remove user from its group, and free it */ +void mwSametimeUser_free(struct mwSametimeUser *u); + + +struct mwSametimeGroup *mwSametimeUser_getGroup(struct mwSametimeUser *u); + + +enum mwSametimeUserType mwSametimeUser_getType(struct mwSametimeUser *u); + + +const char *mwSametimeUser_getUser(struct mwSametimeUser *u); + + +const char *mwSametimeUser_getCommunity(struct mwSametimeUser *u); + + +void mwSametimeUser_setShortName(struct mwSametimeUser *u, const char *name); + + +const char *mwSametimeUser_getShortName(struct mwSametimeUser *u); + + +void mwSametimeUser_setAlias(struct mwSametimeUser *u, const char *alias); + + +const char *mwSametimeUser_getAlias(struct mwSametimeUser *u); + + + +#ifdef __cplusplus +} +#endif + + +#endif /* _MW_ST_LIST_H */ diff --git a/protocols/Sametime/src/meanwhile/src/mw_util.c b/protocols/Sametime/src/meanwhile/src/mw_util.c new file mode 100644 index 0000000000..57c1845b38 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_util.c @@ -0,0 +1,80 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include "mw_util.h" + + +static void collect_keys(gpointer key, gpointer val, gpointer data) { +  GList **list = data; +  *list = g_list_append(*list, key); +} + + +GList *map_collect_keys(GHashTable *ht) { +  GList *ret = NULL; +  g_hash_table_foreach(ht, collect_keys, &ret); +  return ret; +} + + +static void collect_values(gpointer key, gpointer val, gpointer data) { +  GList **list = data; +  *list = g_list_append(*list, val); +} + + +GList *map_collect_values(GHashTable *ht) { +  GList *ret = NULL; +  g_hash_table_foreach(ht, collect_values, &ret); +  return ret; +} + + +struct mw_datum *mw_datum_new(gpointer data, GDestroyNotify clear) { +  struct mw_datum *d = g_new(struct mw_datum, 1); +  mw_datum_set(d, data, clear); +  return d; +} + + +void mw_datum_set(struct mw_datum *d, gpointer data, GDestroyNotify clear) { +  d->data = data; +  d->clear = clear; +} + + +gpointer mw_datum_get(struct mw_datum *d) { +  return d->data; +} + + +void mw_datum_clear(struct mw_datum *d) { +  if(d->clear) { +    d->clear(d->data); +    d->clear = NULL; +  } +  d->data = NULL; +} + + +void mw_datum_free(struct mw_datum *d) { +  mw_datum_clear(d); +  g_free(d); +} diff --git a/protocols/Sametime/src/meanwhile/src/mw_util.h b/protocols/Sametime/src/meanwhile/src/mw_util.h new file mode 100644 index 0000000000..b8e0b7e968 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/mw_util.h @@ -0,0 +1,85 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _MW_UTIL_H +#define _MW_UTIL_H + + +#include <glib.h> +#include <glib/ghash.h> +#include <glib/glist.h> + + +#define map_guint_new() \ +  g_hash_table_new(g_direct_hash, g_direct_equal) + + +#define map_guint_new_full(valfree) \ +  g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (valfree)) + + +#define map_guint_insert(ht, key, val) \ +  g_hash_table_insert((ht), GUINT_TO_POINTER((guint)(key)), (val)) + + +#define map_guint_replace(ht, key, val) \ +  g_hash_table_replace((ht), GUINT_TO_POINTER((guint)(key)), (val)) + + +#define map_guint_lookup(ht, key) \ +  g_hash_table_lookup((ht), GUINT_TO_POINTER((guint)(key))) + + +#define map_guint_remove(ht, key) \ +  g_hash_table_remove((ht), GUINT_TO_POINTER((guint)(key))) + + +#define map_guint_steal(ht, key) \ +  g_hash_table_steal((ht), GUINT_TO_POINTER((guint)(key))) + + +GList *map_collect_keys(GHashTable *ht); + + +GList *map_collect_values(GHashTable *ht); + + +struct mw_datum { +  gpointer data; +  GDestroyNotify clear; +}; + + +struct mw_datum *mw_datum_new(gpointer data, GDestroyNotify clear); + + +void mw_datum_set(struct mw_datum *d, gpointer data, GDestroyNotify clear); + + +gpointer mw_datum_get(struct mw_datum *d); + + +void mw_datum_clear(struct mw_datum *d); + + +void mw_datum_free(struct mw_datum *d); + + +#endif diff --git a/protocols/Sametime/src/meanwhile/src/service.c b/protocols/Sametime/src/meanwhile/src/service.c new file mode 100644 index 0000000000..9ff8d8639f --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/service.c @@ -0,0 +1,267 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include "mw_channel.h" +#include "mw_debug.h" +#include "mw_error.h" +#include "mw_message.h" +#include "mw_service.h" + + +/* I tried to be explicit with the g_return_* calls, to make the debug +   logging a bit more sensible. Hence all the explicit "foo != NULL" +   checks. */ + + +void mwService_recvCreate(struct mwService *s, struct mwChannel *chan, +			  struct mwMsgChannelCreate *msg) { + +  /* ensure none are null, ensure that the service and channel belong +     to the same session, and ensure that the message belongs on the +     channel */ +  g_return_if_fail(s != NULL); +  g_return_if_fail(chan != NULL); +  g_return_if_fail(msg != NULL); +  g_return_if_fail(s->session == mwChannel_getSession(chan)); +  g_return_if_fail(mwChannel_getId(chan) == msg->channel); + +  if(s->recv_create) { +    s->recv_create(s, chan, msg); +  } else { +    mwChannel_destroy(chan, ERR_FAILURE, NULL); +  } +} + + +void mwService_recvAccept(struct mwService *s, struct mwChannel *chan, +			  struct mwMsgChannelAccept *msg) { + +  /* ensure none are null, ensure that the service and channel belong +     to the same session, and ensure that the message belongs on the +     channel */ +  g_return_if_fail(s != NULL); +  g_return_if_fail(chan != NULL); +  g_return_if_fail(msg != NULL); +  g_return_if_fail(s->session == mwChannel_getSession(chan)); +  g_return_if_fail(mwChannel_getId(chan) == msg->head.channel); + +  if(s->recv_accept) +    s->recv_accept(s, chan, msg); +} + + +void mwService_recvDestroy(struct mwService *s, struct mwChannel *chan, +			   struct mwMsgChannelDestroy *msg) { + +  /* ensure none are null, ensure that the service and channel belong +     to the same session, and ensure that the message belongs on the +     channel */ +  g_return_if_fail(s != NULL); +  g_return_if_fail(chan != NULL); +  g_return_if_fail(msg != NULL); +  g_return_if_fail(s->session == mwChannel_getSession(chan)); +  g_return_if_fail(mwChannel_getId(chan) == msg->head.channel); + +  if(s->recv_destroy) +    s->recv_destroy(s, chan, msg); +} + + +void mwService_recv(struct mwService *s, struct mwChannel *chan, +		    guint16 msg_type, struct mwOpaque *data) { + +  /* ensure that none are null. zero-length messages are acceptable */ +  g_return_if_fail(s != NULL); +  g_return_if_fail(chan != NULL); +  g_return_if_fail(data != NULL); +  g_return_if_fail(s->session == mwChannel_getSession(chan)); + +  /* +  g_message("mwService_recv: session = %p, service = %p, b = %p, n = %u", +	    mwService_getSession(s), s, data->data, data->len); +  */ + +  if(s->recv) +    s->recv(s, chan, msg_type, data); +} + + +guint32 mwService_getType(struct mwService *s) { +  g_return_val_if_fail(s != NULL, 0x00); +  return s->type; +} + + +const char *mwService_getName(struct mwService *s) { +  g_return_val_if_fail(s != NULL, NULL); +  g_return_val_if_fail(s->get_name != NULL, NULL); + +  return s->get_name(s); +} + + +const char *mwService_getDesc(struct mwService *s) { +  g_return_val_if_fail(s != NULL, NULL); +  g_return_val_if_fail(s->get_desc != NULL, NULL); + +  return s->get_desc(s); +} + + +struct mwSession *mwService_getSession(struct mwService *s) { +  g_return_val_if_fail(s != NULL, NULL); +  return s->session; +} + + +void mwService_init(struct mwService *srvc, struct mwSession *sess, +		    guint32 type) { + +  /* ensure nothing is null, and there's no such thing as a zero +     service type */ +  g_return_if_fail(srvc != NULL); +  g_return_if_fail(sess != NULL); +  g_return_if_fail(type != 0x00); + +  srvc->session = sess; +  srvc->type = type; +  srvc->state = mwServiceState_STOPPED; +} + + +enum mwServiceState mwService_getState(struct mwService *srvc) { +  g_return_val_if_fail(srvc != NULL, mwServiceState_STOPPED); +  return srvc->state; +} + + +void mwService_start(struct mwService *srvc) { +  g_return_if_fail(srvc != NULL); + +  if(! MW_SERVICE_IS_STOPPED(srvc)) +    return; + +  srvc->state = mwServiceState_STARTING; +  g_message("starting service %s", NSTR(mwService_getName(srvc))); + +  if(srvc->start) { +    srvc->start(srvc); +  } else { +    mwService_started(srvc); +  } +} + + +void mwService_started(struct mwService *srvc) { +  g_return_if_fail(srvc != NULL); + +  srvc->state = mwServiceState_STARTED; +  g_message("started service %s", NSTR(mwService_getName(srvc))); +} + + +void mwService_error(struct mwService *srvc) { +  g_return_if_fail(srvc != NULL); + +  if(MW_SERVICE_IS_DEAD(srvc)) +    return; + +  srvc->state = mwServiceState_ERROR; +  g_message("error in service %s", NSTR(mwService_getName(srvc))); + +  if(srvc->stop) { +    srvc->stop(srvc); +  } else { +    mwService_stopped(srvc); +  } +} + + +void mwService_stop(struct mwService *srvc) { +  g_return_if_fail(srvc != NULL); + +  if(MW_SERVICE_IS_DEAD(srvc)) +    return; + +  srvc->state = mwServiceState_STOPPING; +  g_message("stopping service %s", NSTR(mwService_getName(srvc))); + +  if(srvc->stop) { +    srvc->stop(srvc); +  } else { +    mwService_stopped(srvc); +  } +} + + +void mwService_stopped(struct mwService *srvc) { +  g_return_if_fail(srvc != NULL); + +  if(srvc->state != mwServiceState_STOPPED) { +    srvc->state = mwServiceState_STOPPED; +    g_message("stopped service %s", NSTR(mwService_getName(srvc))); +  } +} + + +void mwService_free(struct mwService *srvc) { +  g_return_if_fail(srvc != NULL); + +  mwService_stop(srvc); + +  if(srvc->clear) +    srvc->clear(srvc); + +  if(srvc->client_cleanup) +    srvc->client_cleanup(srvc->client_data); + +  g_free(srvc); +} + + +/** @todo switch the following to using mw_datum */ + +void mwService_setClientData(struct mwService *srvc, +			     gpointer data, GDestroyNotify cleanup) { + +  g_return_if_fail(srvc != NULL); + +  srvc->client_data = data; +  srvc->client_cleanup = cleanup; +} + + +gpointer mwService_getClientData(struct mwService *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return srvc->client_data; +} + + +void mwService_removeClientData(struct mwService *srvc) { +  g_return_if_fail(srvc != NULL); + +  if(srvc->client_cleanup) { +    srvc->client_cleanup(srvc->client_data); +    srvc->client_cleanup = NULL; +  } + +  srvc->client_data = NULL; +} + diff --git a/protocols/Sametime/src/meanwhile/src/session.c b/protocols/Sametime/src/meanwhile/src/session.c new file mode 100644 index 0000000000..6c116b7a58 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/session.c @@ -0,0 +1,1220 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <glib.h> +#include <string.h> + +#include "mw_channel.h" +#include "mw_cipher.h" +#include "mw_debug.h" +#include "mw_error.h" +#include "mw_message.h" +#include "mw_service.h" +#include "mw_session.h" +#include "mw_util.h" + + +/** the hash table key for a service, for mwSession::services */ +#define SERVICE_KEY(srvc) mwService_getType(srvc) + +/** the hash table key for a cipher, for mwSession::ciphers */ +#define CIPHER_KEY(ciph)  mwCipher_getType(ciph) + + +#define GPOINTER(val)  (GUINT_TO_POINTER((guint) (val))) +#define GUINT(val)     (GPOINTER_TO_UINT((val))) + + +struct mwSession { + +  /** provides I/O and callback functions */ +  struct mwSessionHandler *handler; + +  enum mwSessionState state;  /**< session state */ +  gpointer state_info;        /**< additional state info */ + +  /* input buffering for an incoming message */ +  guchar *buf;  /**< buffer for incoming message data */ +  gsize buf_len;       /**< length of buf */ +  gsize buf_used;      /**< offset to last-used byte of buf */ +   +  struct mwLoginInfo login;      /**< login information */ +  struct mwUserStatus status;    /**< user status */ +  struct mwPrivacyInfo privacy;  /**< privacy list */ + +  /** the collection of channels */ +  struct mwChannelSet *channels; + +  /** the collection of services, keyed to guint32 service id */ +  GHashTable *services; + +  /** the collection of ciphers, keyed to guint16 cipher type */ +  GHashTable *ciphers; + +  /** arbitrary key:value pairs */ +  GHashTable *attributes; + +  /** optional user data */ +  struct mw_datum client_data; +}; + + +static void property_set(struct mwSession *s, const char *key, +			 gpointer val, GDestroyNotify clean) { + +  g_hash_table_insert(s->attributes, g_strdup(key), +		      mw_datum_new(val, clean)); +} + + +static gpointer property_get(struct mwSession *s, const char *key) { +  struct mw_datum *p = g_hash_table_lookup(s->attributes, key); +  return p? p->data: NULL; +} + + +static void property_del(struct mwSession *s, const char *key) { +  g_hash_table_remove(s->attributes, key); +} + + +/** +   set up the default properties for a newly created session +*/ +static void session_defaults(struct mwSession *s) { +  property_set(s, mwSession_CLIENT_VER_MAJOR, +	       GPOINTER(MW_PROTOCOL_VERSION_MAJOR), NULL); + +  property_set(s, mwSession_CLIENT_VER_MINOR,  +	       GPOINTER(MW_PROTOCOL_VERSION_MINOR), NULL); + +  property_set(s, mwSession_CLIENT_TYPE_ID, +	       GPOINTER(mwLogin_MEANWHILE), NULL); +} + + +struct mwSession *mwSession_new(struct mwSessionHandler *handler) { +  struct mwSession *s; + +  g_return_val_if_fail(handler != NULL, NULL); + +  /* consider io_write and io_close to be absolute necessities */ +  g_return_val_if_fail(handler->io_write != NULL, NULL); +  g_return_val_if_fail(handler->io_close != NULL, NULL); + +  s = g_new0(struct mwSession, 1); + +  s->state = mwSession_STOPPED; + +  s->handler = handler; + +  s->channels = mwChannelSet_new(s); +  s->services = map_guint_new(); +  s->ciphers = map_guint_new(); + +  s->attributes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, +					(GDestroyNotify) mw_datum_free); + +  session_defaults(s); + +  return s; +} + + +/** free and reset the session buffer */ +static void session_buf_free(struct mwSession *s) { +  g_return_if_fail(s != NULL); + +  g_free(s->buf); +  s->buf = NULL; +  s->buf_len = 0; +  s->buf_used = 0; +} + + +/** a polite string version of the session state enum */ +static const char *state_str(enum mwSessionState state) { +  switch(state) { +  case mwSession_STARTING:      return "starting"; +  case mwSession_HANDSHAKE:     return "handshake sent"; +  case mwSession_HANDSHAKE_ACK: return "handshake acknowledged"; +  case mwSession_LOGIN:         return "login sent"; +  case mwSession_LOGIN_REDIR:   return "login redirected"; +  case mwSession_LOGIN_CONT:    return "forcing login"; +  case mwSession_LOGIN_ACK:     return "login acknowledged"; +  case mwSession_STARTED:       return "started"; +  case mwSession_STOPPING:      return "stopping"; +  case mwSession_STOPPED:       return "stopped"; + +  case mwSession_UNKNOWN:       /* fall-through */ +  default:                      return "UNKNOWN"; +  } +} + + +void mwSession_free(struct mwSession *s) { +  struct mwSessionHandler *h; + +  g_return_if_fail(s != NULL); + +  if(! mwSession_isStopped(s)) { +    g_debug("session is not stopped (state: %s), proceeding with free", +	    state_str(s->state)); +  } + +  h = s->handler; +  if(h && h->clear) h->clear(s); +  s->handler = NULL; + +  session_buf_free(s); + +  mwChannelSet_free(s->channels); +  g_hash_table_destroy(s->services); +  g_hash_table_destroy(s->ciphers); +  g_hash_table_destroy(s->attributes); + +  mwLoginInfo_clear(&s->login); +  mwUserStatus_clear(&s->status); +  mwPrivacyInfo_clear(&s->privacy); + +  g_free(s); +} + + +/** write data to the session handler */ +static int io_write(struct mwSession *s, const guchar *buf, gsize len) { +  g_return_val_if_fail(s != NULL, -1); +  g_return_val_if_fail(s->handler != NULL, -1); +  g_return_val_if_fail(s->handler->io_write != NULL, -1); + +  return s->handler->io_write(s, buf, len); +} + + +/** close the session handler */ +static void io_close(struct mwSession *s) { +  g_return_if_fail(s != NULL); +  g_return_if_fail(s->handler != NULL); +  g_return_if_fail(s->handler->io_close != NULL); + +  s->handler->io_close(s); +} + + +static void state(struct mwSession *s, enum mwSessionState state, +		  gpointer info) { + +  struct mwSessionHandler *sh; + +  g_return_if_fail(s != NULL); +  g_return_if_fail(s->handler != NULL); + +  if(mwSession_isState(s, state)) return; + +  s->state = state; +  s->state_info = info; + +  switch(state) { +  case mwSession_STOPPING: +  case mwSession_STOPPED: +    g_message("session state: %s (0x%08x)", state_str(state), +	      GPOINTER_TO_UINT(info)); +    break; + +  case mwSession_LOGIN_REDIR: +	/// Miranda NG adaptation - start - https://developer.pidgin.im/ticket/7563#comment:4 +    //g_message("session state: %s (%s)", state_str(state), (char *)info); +    g_message("session state: %s (%s)", state_str(state), NSTR((char *)info)); +	/// Miranda NG adaptation - end +    break; + +  default: +    g_message("session state: %s", state_str(state)); +  } + +  sh = s->handler; +  if(sh && sh->on_stateChange) +    sh->on_stateChange(s, state, info); +} + + +void mwSession_start(struct mwSession *s) { +  struct mwMsgHandshake *msg; +  int ret; + +  g_return_if_fail(s != NULL); +  g_return_if_fail(mwSession_isStopped(s)); + +  if(mwSession_isStarted(s) || mwSession_isStarting(s)) { +    g_debug("attempted to start session that is already started/starting"); +    return; +  } +   +  state(s, mwSession_STARTING, 0); + +  msg = (struct mwMsgHandshake *) mwMessage_new(mwMessage_HANDSHAKE); +  msg->major = GUINT(property_get(s, mwSession_CLIENT_VER_MAJOR)); +  msg->minor = GUINT(property_get(s, mwSession_CLIENT_VER_MINOR)); +  msg->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID)); + +  msg->loclcalc_addr = GUINT(property_get(s, mwSession_CLIENT_IP)); + +  if(msg->major >= 0x001e && msg->minor >= 0x001d) { +    msg->unknown_a = 0x0100; +    msg->local_host = property_get(s, mwSession_CLIENT_HOST); +  } + +  ret = mwSession_send(s, MW_MESSAGE(msg)); +  mwMessage_free(MW_MESSAGE(msg)); + +  if(ret) { +    mwSession_stop(s, CONNECTION_BROKEN); +  } else { +    state(s, mwSession_HANDSHAKE, 0); +  } +} + + +void mwSession_stop(struct mwSession *s, guint32 reason) { +  GList *list, *l = NULL; +  struct mwMsgChannelDestroy *msg; + +  g_return_if_fail(s != NULL); +   +  if(mwSession_isStopped(s) || mwSession_isStopping(s)) { +    g_debug("attempted to stop session that is already stopped/stopping"); +    return; +  } + +  state(s, mwSession_STOPPING, GUINT_TO_POINTER(reason)); + +  for(list = l = mwSession_getServices(s); l; l = l->next) +    mwService_stop(MW_SERVICE(l->data)); +  g_list_free(list); + +  msg = (struct mwMsgChannelDestroy *) +    mwMessage_new(mwMessage_CHANNEL_DESTROY); + +  msg->head.channel = MW_MASTER_CHANNEL_ID; +  msg->reason = reason; + +  /* don't care if this fails, we're closing the connection anyway */ +  mwSession_send(s, MW_MESSAGE(msg)); +  mwMessage_free(MW_MESSAGE(msg)); + +  session_buf_free(s); + +  /* close the connection */ +  io_close(s); + +  state(s, mwSession_STOPPED, GUINT_TO_POINTER(reason)); +} + + +/** compose authentication information into an opaque based on the +    password, encrypted via RC2/40 */ +static void compose_auth_rc2_40(struct mwOpaque *auth, const char *pass) { +  guchar iv[8], key[5]; +  struct mwOpaque a, b, z; +  struct mwPutBuffer *p; + +  /* get an IV and a random five-byte key */ +  mwIV_init(iv); +  mwKeyRandom(key, 5); + +  /* the opaque with the key */ +  a.len = 5; +  a.data = key; + +  /* the opaque to receive the encrypted pass */ +  b.len = 0; +  b.data = NULL; + +  /* the plain-text pass dressed up as an opaque */ +  z.len = strlen(pass); +  z.data = (guchar *) pass; + +  /* the opaque with the encrypted pass */ +  mwEncrypt(a.data, a.len, iv, &z, &b); + +  /* an opaque containing the other two opaques */ +  p = mwPutBuffer_new(); +  mwOpaque_put(p, &a); +  mwOpaque_put(p, &b); +  mwPutBuffer_finalize(auth, p); + +  /* this is the only one to clear, as the other uses a static buffer */ +  mwOpaque_clear(&b); +} + + +static void compose_auth_rc2_128(struct mwOpaque *auth, const char *pass, +				 guint32 magic, struct mwOpaque *rkey) { + +  guchar iv[8]; +  struct mwOpaque a, b, c; +  struct mwPutBuffer *p; + +  struct mwMpi *private, *public; +  struct mwMpi *remote; +  struct mwMpi *shared; + +  private = mwMpi_new(); +  public = mwMpi_new(); +  remote = mwMpi_new(); +  shared = mwMpi_new(); + +  mwIV_init(iv); + +  mwMpi_randDHKeypair(private, public); +  mwMpi_import(remote, rkey); +  mwMpi_calculateDHShared(shared, remote, private); + +  /* put the password in opaque a */ +  p = mwPutBuffer_new(); +  guint32_put(p, magic); +  mwString_put(p, pass); +  mwPutBuffer_finalize(&a, p); + +  /* put the shared key in opaque b */ +  mwMpi_export(shared, &b); + +  /* encrypt the password (a) using the shared key (b), put the result +     in opaque c */ +  mwEncrypt(b.data+(b.len-16), 16, iv, &a, &c); + +  /* don't need the shared key anymore, re-use opaque (b) as the +     export of the public key */ +  mwOpaque_clear(&b); +  mwMpi_export(public, &b); + +  p = mwPutBuffer_new(); +  guint16_put(p, 0x0001);  /* XXX: unknown */ +  mwOpaque_put(p, &b); +  mwOpaque_put(p, &c); +  mwPutBuffer_finalize(auth, p); + +  mwOpaque_clear(&a); +  mwOpaque_clear(&b); +  mwOpaque_clear(&c); + +  mwMpi_free(private); +  mwMpi_free(public); +  mwMpi_free(remote); +  mwMpi_free(shared); +} + + +/** handle the receipt of a handshake_ack message by sending the login +    message */ +static void HANDSHAKE_ACK_recv(struct mwSession *s, +			       struct mwMsgHandshakeAck *msg) { +  struct mwMsgLogin *log; +  int ret; +			        +  g_return_if_fail(s != NULL); +  g_return_if_fail(msg != NULL); +  g_return_if_fail(mwSession_isState(s, mwSession_HANDSHAKE) || +		   mwSession_isState(s, mwSession_LOGIN_CONT)); + +  if(mwSession_isState(s, mwSession_LOGIN_CONT)) { +    /* this is a login continuation, don't re-send the login. We +       should receive a login ack in a moment */ + +    state(s, mwSession_HANDSHAKE_ACK, 0); +    state(s, mwSession_LOGIN, 0); +    return; + +  } else { +    state(s, mwSession_HANDSHAKE_ACK, 0); +  } + +  /* record the major/minor versions from the server */ +  property_set(s, mwSession_SERVER_VER_MAJOR, GPOINTER(msg->major), NULL); +  property_set(s, mwSession_SERVER_VER_MINOR, GPOINTER(msg->minor), NULL); + +  /* compose the login message */ +  log = (struct mwMsgLogin *) mwMessage_new(mwMessage_LOGIN); +  log->login_type = GUINT(property_get(s, mwSession_CLIENT_TYPE_ID)); +  log->name = g_strdup(property_get(s, mwSession_AUTH_USER_ID)); + +  /** @todo default to password for now. later use token optionally */ +  { +    const char *pw; +    pw = property_get(s, mwSession_AUTH_PASSWORD); +    +    if(msg->data.len >= 64) { +      /* good login encryption */ +      log->auth_type = mwAuthType_RC2_128; +      compose_auth_rc2_128(&log->auth_data, pw, msg->magic, &msg->data); + +    } else { +      /* BAD login encryption */ +      log->auth_type = mwAuthType_RC2_40; +      compose_auth_rc2_40(&log->auth_data, pw); +    } +  } +   +  /* send the login message */ +  ret = mwSession_send(s, MW_MESSAGE(log)); +  mwMessage_free(MW_MESSAGE(log)); + +  if(! ret) { +    /* sent login OK, set state appropriately */ +    state(s, mwSession_LOGIN, 0); +  } +} + + +/** handle the receipt of a login_ack message. This completes the +    startup sequence for the session */ +static void LOGIN_ACK_recv(struct mwSession *s, +			   struct mwMsgLoginAck *msg) { +  GList *ll, *l; + +  g_return_if_fail(s != NULL); +  g_return_if_fail(msg != NULL); +  g_return_if_fail(mwSession_isState(s, mwSession_LOGIN)); + +  /* store the login information in the session */ +  mwLoginInfo_clear(&s->login); +  mwLoginInfo_clone(&s->login, &msg->login); + +  state(s, mwSession_LOGIN_ACK, 0); + +  /* start up our services */ +  for(ll = l = mwSession_getServices(s); l; l = l->next) { +    mwService_start(l->data); +  } +  g_list_free(ll); + +  /* @todo any further startup stuff? */ + +  state(s, mwSession_STARTED, 0); +} + + +static void CHANNEL_CREATE_recv(struct mwSession *s, +				struct mwMsgChannelCreate *msg) { +  struct mwChannel *chan; +  chan = mwChannel_newIncoming(s->channels, msg->channel); + +  /* hand off to channel */ +  mwChannel_recvCreate(chan, msg); +} + + +static void CHANNEL_ACCEPT_recv(struct mwSession *s, +				struct mwMsgChannelAccept *msg) { +  struct mwChannel *chan; +  chan = mwChannel_find(s->channels, msg->head.channel); + +  g_return_if_fail(chan != NULL); + +  /* hand off to channel */ +  mwChannel_recvAccept(chan, msg); +} + + +static void CHANNEL_DESTROY_recv(struct mwSession *s, +				 struct mwMsgChannelDestroy *msg) { + +  /* the server can indicate that we should close the session by +     destroying the zero channel */ +  if(msg->head.channel == MW_MASTER_CHANNEL_ID) { +    mwSession_stop(s, msg->reason); + +  } else { +    struct mwChannel *chan; +    chan = mwChannel_find(s->channels, msg->head.channel); + +    /* we don't have any such channel... so I guess we destroyed it. +       This is to remove a warning from timing errors when two clients +       both try to close a channel at about the same time. */ +    if(! chan) return; +     +    /* hand off to channel */ +    mwChannel_recvDestroy(chan, msg); +  } +} + + +static void CHANNEL_SEND_recv(struct mwSession *s, +			      struct mwMsgChannelSend *msg) { +  struct mwChannel *chan; +  chan = mwChannel_find(s->channels, msg->head.channel); + +  /* if we don't have any such channel, we're certainly not going to +     accept data from it */ +  if(! chan) return; + +  /* hand off to channel */ +  mwChannel_recv(chan, msg); +} + + +static void SET_PRIVACY_LIST_recv(struct mwSession *s, +				  struct mwMsgSetPrivacyList *msg) { +  struct mwSessionHandler *sh = s->handler; + +  /// Miranda NG adaptation start - MSVC +  ///g_info("SET_PRIVACY_LIST"); +  g_message("SET_PRIVACY_LIST"); +  /// Miranda NG adaptation end + +  mwPrivacyInfo_clear(&s->privacy); +  mwPrivacyInfo_clone(&s->privacy, &msg->privacy); + +  if(sh && sh->on_setPrivacyInfo) +    sh->on_setPrivacyInfo(s); +} + + +static void SET_USER_STATUS_recv(struct mwSession *s, +				 struct mwMsgSetUserStatus *msg) { +  struct mwSessionHandler *sh = s->handler; + +  mwUserStatus_clear(&s->status); +  mwUserStatus_clone(&s->status, &msg->status); + +  if(sh && sh->on_setUserStatus) +    sh->on_setUserStatus(s); +} + + +static void SENSE_SERVICE_recv(struct mwSession *s, +			       struct mwMsgSenseService *msg) { +  struct mwService *srvc; + +  srvc = mwSession_getService(s, msg->service); +  if(srvc) mwService_start(srvc); +} + + +static void ADMIN_recv(struct mwSession *s, struct mwMsgAdmin *msg) { +  struct mwSessionHandler *sh = s->handler; + +  if(sh && sh->on_admin) +    sh->on_admin(s, msg->text); +} + + +static void ANNOUNCE_recv(struct mwSession *s, struct mwMsgAnnounce *msg) { +  struct mwSessionHandler *sh = s->handler; + +  if(sh && sh->on_announce) +    sh->on_announce(s, &msg->sender, msg->may_reply, msg->text); +} + + +static void LOGIN_REDIRECT_recv(struct mwSession *s, +				struct mwMsgLoginRedirect *msg) { + +  state(s, mwSession_LOGIN_REDIR, msg->host); +} + + +#define CASE(var, type) \ +case mwMessage_ ## var: \ +  var ## _recv(s, (struct type *) msg); \ +  break; + + +static void session_process(struct mwSession *s, +			    const guchar *buf, gsize len) { + +  /// Miranda NG adaptation start - MSVC +  /// struct mwOpaque o = { .len = len, .data = (guchar *) buf }; +  struct mwOpaque o; +  /// Miranda NG adaptation end + +  struct mwGetBuffer *b; +  struct mwMessage *msg; + +  /// Miranda NG adaptation start - MSVC +  o.len = len; +  o.data = (guchar*) buf; +  /// Miranda NG adaptation end + +  g_return_if_fail(s != NULL); +  g_return_if_fail(buf != NULL); + +  /* ignore zero-length messages */ +  if(len == 0) return; + +  /* wrap up buf */ +  b = mwGetBuffer_wrap(&o); + +  /* attempt to parse the message. */ +  msg = mwMessage_get(b); + +  if(mwGetBuffer_error(b)) { +    mw_mailme_opaque(&o, "parsing of message failed"); +  } + +  mwGetBuffer_free(b); + +  g_return_if_fail(msg != NULL); + +  /* handle each of the appropriate incoming types of mwMessage */ +  switch(msg->type) { +    CASE(HANDSHAKE_ACK, mwMsgHandshakeAck); +    CASE(LOGIN_REDIRECT, mwMsgLoginRedirect); +    CASE(LOGIN_ACK, mwMsgLoginAck); +    CASE(CHANNEL_CREATE, mwMsgChannelCreate); +    CASE(CHANNEL_DESTROY, mwMsgChannelDestroy); +    CASE(CHANNEL_SEND, mwMsgChannelSend); +    CASE(CHANNEL_ACCEPT, mwMsgChannelAccept); +    CASE(SET_PRIVACY_LIST, mwMsgSetPrivacyList); +    CASE(SET_USER_STATUS, mwMsgSetUserStatus); +    CASE(SENSE_SERVICE, mwMsgSenseService); +    CASE(ADMIN, mwMsgAdmin); +    CASE(ANNOUNCE, mwMsgAnnounce); +     +  default: +    g_warning("unknown message type 0x%04x, no handler", msg->type); +  } + +  mwMessage_free(msg); +} + + +#undef CASE + + +#define ADVANCE(b, n, count) { b += count; n -= count; } + + +/* handle input to complete an existing buffer */ +static gsize session_recv_cont(struct mwSession *s, +			       const guchar *b, gsize n) { + +  /* determine how many bytes still required */ +  gsize x = s->buf_len - s->buf_used; + +  /* g_message(" session_recv_cont: session = %p, b = %p, n = %u", +	    s, b, n); */ +   +  if(n < x) { +    /* not quite enough; still need some more */ +    memcpy(s->buf+s->buf_used, b, n); +    s->buf_used += n; +    return 0; +     +  } else { +    /* enough to finish the buffer, at least */ +    memcpy(s->buf+s->buf_used, b, x); +    ADVANCE(b, n, x); +     +    if(s->buf_len == 4) { +      /* if only the length bytes were being buffered, we'll now try +       to complete an actual message */ + +      struct mwOpaque o = { 4, s->buf }; +      struct mwGetBuffer *gb = mwGetBuffer_wrap(&o); +      x = guint32_peek(gb); +      mwGetBuffer_free(gb); + +      if(n < x) { +	/* there isn't enough to meet the demands of the length, so +	   we'll buffer it for next time */ + +	guchar *t; +	x += 4; +	t = (guchar *) g_malloc(x); +	memcpy(t, s->buf, 4); +	memcpy(t+4, b, n); +	 +	session_buf_free(s); +	 +	s->buf = t; +	s->buf_len = x; +	s->buf_used = n + 4; +	return 0; +	 +      } else { +	/* there's enough (maybe more) for a full message. don't need +	   the old session buffer (which recall, was only the length +	   bytes) any more */ +	 +	session_buf_free(s); +	session_process(s, b, x); +	ADVANCE(b, n, x); +      } +       +    } else { +      /* process the now-complete buffer. remember to skip the first +	 four bytes, since they're just the size count */ +      session_process(s, s->buf+4, s->buf_len-4); +      session_buf_free(s); +    } +  } + +  return n; +} + + +/* handle input when there's nothing previously buffered */ +static gsize session_recv_empty(struct mwSession *s, +				const guchar *b, gsize n) { + +  struct mwOpaque o = { n, (guchar *) b }; +  struct mwGetBuffer *gb; +  gsize x; + +  if(n < 4) { +    /* uh oh. less than four bytes means we've got an incomplete +       length indicator. Have to buffer to get the rest of it. */ +    s->buf = (guchar *) g_malloc0(4); +    memcpy(s->buf, b, n); +    s->buf_len = 4; +    s->buf_used = n; +    return 0; +  } +   +  /* peek at the length indicator. if it's a zero length message, +     don't process, just skip it */ +  gb = mwGetBuffer_wrap(&o); +  x = guint32_peek(gb); +  mwGetBuffer_free(gb); +  if(! x) return n - 4; + +  if(n < (x + 4)) { +    /* if the total amount of data isn't enough to cover the length +       bytes and the length indicated by those bytes, then we'll need +       to buffer. This is where the DOS mentioned below in +       session_recv takes place */ + +    x += 4; +    s->buf = (guchar *) g_malloc(x); +    memcpy(s->buf, b, n); +    s->buf_len = x; +    s->buf_used = n; +    return 0; +     +  } else { +    /* advance past length bytes */ +    ADVANCE(b, n, 4); +     +    /* process and advance */ +    session_process(s, b, x); +    ADVANCE(b, n, x); + +    /* return left-over count */ +    return n; +  } +} + + +static gsize session_recv(struct mwSession *s, +			  const guchar *b, gsize n) { + +  /* This is messy and kind of confusing. I'd like to simplify it at +     some point, but the constraints are as follows: + +      - buffer up to a single full message on the session buffer +      - buffer must contain the four length bytes +      - the four length bytes indicate how much we'll need to buffer +      - the four length bytes might not arrive all at once, so it's +        possible that we'll need to buffer to get them. +      - since our buffering includes the length bytes, we know we +        still have an incomplete length if the buffer length is only +        four. */ +   +  /** @todo we should allow a compiled-in upper limit to message +     sizes, and just drop messages over that size. However, to do that +     we'd need to keep track of the size of a message and keep +     dropping bytes until we'd fulfilled the entire length. eg: if we +     receive a message size of 10MB, we need to pass up exactly 10MB +     before it's safe to start processing the rest as a new +     message. As it stands, a malicious packet from the server can run +     us out of memory by indicating it's going to send us some +     obscenely long message (even if it never actually sends it) */ +   +  /* g_message(" session_recv: session = %p, b = %p, n = %u", +	    s, b, n); */ +   +  if(s->buf_len == 0) { +    while(n && (*b & 0x80)) { +      /* keep-alive and series bytes are ignored */ +      ADVANCE(b, n, 1); +    } +  } + +  if(n == 0) { +    return 0; + +  } else if(s->buf_len > 0) { +    return session_recv_cont(s, b, n); + +  } else { +    return session_recv_empty(s, b, n); +  } +} + + +#undef ADVANCE + + +void mwSession_recv(struct mwSession *s, const guchar *buf, gsize n) { +  guchar *b = (guchar *) buf; +  gsize remain = 0; + +  g_return_if_fail(s != NULL); + +  while(n > 0) { +    remain = session_recv(s, b, n); +    b += (n - remain); +    n = remain; +  } +} + + +int mwSession_send(struct mwSession *s, struct mwMessage *msg) { +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret = 0; + +  g_return_val_if_fail(s != NULL, -1); + +  /* writing nothing is easy */ +  if(! msg) return 0; + +  /* first we render the message into an opaque */ +  b = mwPutBuffer_new(); +  mwMessage_put(b, msg); +  mwPutBuffer_finalize(&o, b); + +  /* then we render the opaque into... another opaque! */ +  b = mwPutBuffer_new(); +  mwOpaque_put(b, &o); +  mwOpaque_clear(&o); +  mwPutBuffer_finalize(&o, b); + +  /* then we use that opaque's data and length to write to the socket */ +  ret = io_write(s, o.data, o.len); +  mwOpaque_clear(&o); + +  /* ensure we could actually write the message */ +  if(! ret) { + +    /* special case, as the server doesn't always respond to user +       status messages. Thus, we trigger the event when we send the +       messages as well as when we receive them */ +    if(msg->type == mwMessage_SET_USER_STATUS) { +      SET_USER_STATUS_recv(s, (struct mwMsgSetUserStatus *) msg); +    } +  } + +  return ret; +} + + +int mwSession_sendKeepalive(struct mwSession *s) { +  const guchar b = 0x80; + +  g_return_val_if_fail(s != NULL, -1); +  return io_write(s, &b, 1); +} + + +int mwSession_forceLogin(struct mwSession *s) { +  struct mwMsgLoginContinue *msg; +  int ret; + +  g_return_val_if_fail(s != NULL, -1); +  g_return_val_if_fail(mwSession_isState(s, mwSession_LOGIN_REDIR), -1); +   +  state(s, mwSession_LOGIN_CONT, 0x00); + +  msg = (struct mwMsgLoginContinue *) +    mwMessage_new(mwMessage_LOGIN_CONTINUE); + +  ret = mwSession_send(s, MW_MESSAGE(msg)); +  mwMessage_free(MW_MESSAGE(msg)); +   +  return ret; +} + + +int mwSession_sendAnnounce(struct mwSession *s, gboolean may_reply, +			   const char *text, const GList *recipients) { + +  struct mwMsgAnnounce *msg; +  int ret; + +  g_return_val_if_fail(s != NULL, -1); +  g_return_val_if_fail(mwSession_isStarted(s), -1); +   +  msg = (struct mwMsgAnnounce *) mwMessage_new(mwMessage_ANNOUNCE); + +  msg->recipients = (GList *) recipients; +  msg->may_reply = may_reply; +  msg->text = g_strdup(text); + +  ret = mwSession_send(s, MW_MESSAGE(msg)); + +  msg->recipients = NULL;  /* don't kill our recipients param */ +  mwMessage_free(MW_MESSAGE(msg)); + +  return ret; +} + + +struct mwSessionHandler *mwSession_getHandler(struct mwSession *s) { +  g_return_val_if_fail(s != NULL, NULL); +  return s->handler; +} + + +struct mwLoginInfo *mwSession_getLoginInfo(struct mwSession *s) { +  g_return_val_if_fail(s != NULL, NULL); +  return &s->login; +} + + +int mwSession_setPrivacyInfo(struct mwSession *s, +			     struct mwPrivacyInfo *privacy) { + +  struct mwMsgSetPrivacyList *msg; +  int ret; + +  g_return_val_if_fail(s != NULL, -1); +  g_return_val_if_fail(privacy != NULL, -1); + +  msg = (struct mwMsgSetPrivacyList *) +    mwMessage_new(mwMessage_SET_PRIVACY_LIST); + +  mwPrivacyInfo_clone(&msg->privacy, privacy); + +  ret = mwSession_send(s, MW_MESSAGE(msg)); +  mwMessage_free(MW_MESSAGE(msg)); + +  return ret; +} + + +struct mwPrivacyInfo *mwSession_getPrivacyInfo(struct mwSession *s) { +  g_return_val_if_fail(s != NULL, NULL); +  return &s->privacy; +} + + +int mwSession_setUserStatus(struct mwSession *s, +			    struct mwUserStatus *stat) { + +  struct mwMsgSetUserStatus *msg; +  int ret; + +  g_return_val_if_fail(s != NULL, -1); +  g_return_val_if_fail(stat != NULL, -1); + +  msg = (struct mwMsgSetUserStatus *) +    mwMessage_new(mwMessage_SET_USER_STATUS); + +  mwUserStatus_clone(&msg->status, stat); + +  ret = mwSession_send(s, MW_MESSAGE(msg)); +  mwMessage_free(MW_MESSAGE(msg)); + +  return ret; +} + + +struct mwUserStatus *mwSession_getUserStatus(struct mwSession *s) { +  g_return_val_if_fail(s != NULL, NULL); +  return &s->status; +} + + +enum mwSessionState mwSession_getState(struct mwSession *s) { +  g_return_val_if_fail(s != NULL, mwSession_UNKNOWN); +  return s->state; +} + + +gpointer mwSession_getStateInfo(struct mwSession *s) { +  g_return_val_if_fail(s != NULL, 0); +  return s->state_info; +} + + +struct mwChannelSet *mwSession_getChannels(struct mwSession *session) { +  g_return_val_if_fail(session != NULL, NULL); +  return session->channels; +} + + +gboolean mwSession_addService(struct mwSession *s, struct mwService *srv) { +  g_return_val_if_fail(s != NULL, FALSE); +  g_return_val_if_fail(srv != NULL, FALSE); +  g_return_val_if_fail(s->services != NULL, FALSE); + +  if(map_guint_lookup(s->services, SERVICE_KEY(srv))) { +    return FALSE; + +  } else { +    map_guint_insert(s->services, SERVICE_KEY(srv), srv); +    if(mwSession_isState(s, mwSession_STARTED)) +      mwSession_senseService(s, mwService_getType(srv)); +    return TRUE; +  } +} + + +struct mwService *mwSession_getService(struct mwSession *s, guint32 srv) { +  g_return_val_if_fail(s != NULL, NULL); +  g_return_val_if_fail(s->services != NULL, NULL); + +  return map_guint_lookup(s->services, srv); +} + + +struct mwService *mwSession_removeService(struct mwSession *s, guint32 srv) { +  struct mwService *svc; + +  g_return_val_if_fail(s != NULL, NULL); +  g_return_val_if_fail(s->services != NULL, NULL); + +  svc = map_guint_lookup(s->services, srv); +  if(svc) map_guint_remove(s->services, srv); +  return svc; +} + + +GList *mwSession_getServices(struct mwSession *s) { +  g_return_val_if_fail(s != NULL, NULL); +  g_return_val_if_fail(s->services != NULL, NULL); + +  return map_collect_values(s->services); +} + + +void mwSession_senseService(struct mwSession *s, guint32 srvc) { +  struct mwMsgSenseService *msg; + +  g_return_if_fail(s != NULL); +  g_return_if_fail(srvc != 0x00); +  g_return_if_fail(mwSession_isStarted(s)); + +  msg = (struct mwMsgSenseService *) +    mwMessage_new(mwMessage_SENSE_SERVICE); +  msg->service = srvc; + +  mwSession_send(s, MW_MESSAGE(msg)); +  mwMessage_free(MW_MESSAGE(msg)); +} + + +gboolean mwSession_addCipher(struct mwSession *s, struct mwCipher *c) { +  g_return_val_if_fail(s != NULL, FALSE); +  g_return_val_if_fail(c != NULL, FALSE); +  g_return_val_if_fail(s->ciphers != NULL, FALSE); + +  if(map_guint_lookup(s->ciphers, mwCipher_getType(c))) { +    g_message("cipher %s is already added, apparently", +	      NSTR(mwCipher_getName(c))); +    return FALSE; + +  } else { +    g_message("adding cipher %s", NSTR(mwCipher_getName(c))); +    map_guint_insert(s->ciphers, mwCipher_getType(c), c); +    return TRUE; +  } +} + + +struct mwCipher *mwSession_getCipher(struct mwSession *s, guint16 c) { +  g_return_val_if_fail(s != NULL, NULL); +  g_return_val_if_fail(s->ciphers != NULL, NULL); + +  return map_guint_lookup(s->ciphers, c); +} + + +struct mwCipher *mwSession_removeCipher(struct mwSession *s, guint16 c) { +  struct mwCipher *ciph; + +  g_return_val_if_fail(s != NULL, NULL); +  g_return_val_if_fail(s->ciphers != NULL, NULL); + +  ciph = map_guint_lookup(s->ciphers, c); +  if(ciph) map_guint_remove(s->ciphers, c); +  return ciph; +} + + +GList *mwSession_getCiphers(struct mwSession *s) { +  g_return_val_if_fail(s != NULL, NULL); +  g_return_val_if_fail(s->ciphers != NULL, NULL); + +  return map_collect_values(s->ciphers); +} + + +void mwSession_setProperty(struct mwSession *s, const char *key, +			   gpointer val, GDestroyNotify clean) { + +  g_return_if_fail(s != NULL); +  g_return_if_fail(s->attributes != NULL); +  g_return_if_fail(key != NULL); + +  property_set(s, key, val, clean); +} + + +gpointer mwSession_getProperty(struct mwSession *s, const char *key) { +  +  g_return_val_if_fail(s != NULL, NULL); +  g_return_val_if_fail(s->attributes != NULL, NULL); +  g_return_val_if_fail(key != NULL, NULL); + +  return property_get(s, key); +} + + +void mwSession_removeProperty(struct mwSession *s, const char *key) { +  g_return_if_fail(s != NULL); +  g_return_if_fail(s->attributes != NULL); +  g_return_if_fail(key != NULL); + +  property_del(s, key); +} + + +void mwSession_setClientData(struct mwSession *session, +			     gpointer data, GDestroyNotify clear) { + +  g_return_if_fail(session != NULL); +  mw_datum_set(&session->client_data, data, clear); +} + + +gpointer mwSession_getClientData(struct mwSession *session) { +  g_return_val_if_fail(session != NULL, NULL); +  return mw_datum_get(&session->client_data); +} + + +void mwSession_removeClientData(struct mwSession *session) { +  g_return_if_fail(session != NULL); +  mw_datum_clear(&session->client_data); +} + diff --git a/protocols/Sametime/src/meanwhile/src/srvc_aware.c b/protocols/Sametime/src/meanwhile/src/srvc_aware.c new file mode 100644 index 0000000000..8c11be229f --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/srvc_aware.c @@ -0,0 +1,1341 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <glib.h> +#include <glib/ghash.h> +#include <glib/glist.h> +#include <string.h> + +#include "mw_channel.h" +#include "mw_debug.h" +#include "mw_error.h" +#include "mw_message.h" +#include "mw_service.h" +#include "mw_session.h" +#include "mw_srvc_aware.h" +#include "mw_util.h" + + +struct mwServiceAware { +  struct mwService service; + +  struct mwAwareHandler *handler; + +  /** map of ENTRY_KEY(aware_entry):aware_entry */ +  GHashTable *entries; + +  /** set of guint32:attrib_watch_entry attribute keys */ +  GHashTable *attribs; + +  /** collection of lists of awareness for this service. Each item is +      a mwAwareList */ +  GList *lists; + +  /** the buddy list channel */ +  struct mwChannel *channel; +}; + + +struct mwAwareList { + +  /** the owning service */ +  struct mwServiceAware *service; + +  /** map of ENTRY_KEY(aware_entry):aware_entry */ +  GHashTable *entries; + +  /** set of guint32:attrib_watch_entry attribute keys */ +  GHashTable *attribs; + +  struct mwAwareListHandler *handler; +  struct mw_datum client_data; +}; + + +struct mwAwareAttribute { +  guint32 key; +  struct mwOpaque data; +}; + + +struct attrib_entry { +  guint32 key; +  GList *membership; +}; + + +/** an actual awareness entry, belonging to any number of aware lists */ +struct aware_entry { +  struct mwAwareSnapshot aware; + +  /** list of mwAwareList containing this entry */ +  GList *membership; + +  /** collection of attribute values for this entry. +      map of ATTRIB_KEY(mwAwareAttribute):mwAwareAttribute */ +  GHashTable *attribs; +}; + + +#define ENTRY_KEY(entry) &entry->aware.id + + +/** the channel send types used by this service */ +enum msg_types { +  msg_AWARE_ADD       = 0x0068,  /**< remove an aware */ +  msg_AWARE_REMOVE    = 0x0069,  /**< add an aware */ + +  msg_OPT_DO_SET      = 0x00c9,  /**< set an attribute */ +  msg_OPT_DO_UNSET    = 0x00ca,  /**< unset an attribute */ +  msg_OPT_WATCH       = 0x00cb,  /**< set the attribute watch list */ + +  msg_AWARE_SNAPSHOT  = 0x01f4,  /**< recv aware snapshot */ +  msg_AWARE_UPDATE    = 0x01f5,  /**< recv aware update */ +  msg_AWARE_GROUP     = 0x01f6,  /**< recv group aware */ + +  msg_OPT_GOT_SET     = 0x0259,  /**< recv attribute set update */ +  msg_OPT_GOT_UNSET   = 0x025a,  /**< recv attribute unset update */ + +  msg_OPT_GOT_UNKNOWN = 0x025b,  /**< UNKNOWN */ +   +  msg_OPT_DID_SET     = 0x025d,  /**< attribute set response */ +  msg_OPT_DID_UNSET   = 0x025e,  /**< attribute unset response */ +  msg_OPT_DID_ERROR   = 0x025f,  /**< attribute set/unset error */ +}; + + +static void aware_entry_free(struct aware_entry *ae) { +  mwAwareSnapshot_clear(&ae->aware); +  g_list_free(ae->membership); +  g_hash_table_destroy(ae->attribs); +  g_free(ae); +} + + +static void attrib_entry_free(struct attrib_entry *ae) { +  g_list_free(ae->membership); +  g_free(ae); +} + + +static void attrib_free(struct mwAwareAttribute *attrib) { +  mwOpaque_clear(&attrib->data); +  g_free(attrib); +} + + +static struct aware_entry *aware_find(struct mwServiceAware *srvc, +				      struct mwAwareIdBlock *srch) { +  g_return_val_if_fail(srvc != NULL, NULL); +  g_return_val_if_fail(srvc->entries != NULL, NULL); +  g_return_val_if_fail(srch != NULL, NULL); +   +  return g_hash_table_lookup(srvc->entries, srch); +} + + +static struct aware_entry *list_aware_find(struct mwAwareList *list, +					   struct mwAwareIdBlock *srch) { +  g_return_val_if_fail(list != NULL, NULL); +  g_return_val_if_fail(list->entries != NULL, NULL); +  g_return_val_if_fail(srch != NULL, NULL); + +  return g_hash_table_lookup(list->entries, srch); +} + + +static void compose_list(struct mwPutBuffer *b, GList *id_list) { +  guint32_put(b, g_list_length(id_list)); +  for(; id_list; id_list = id_list->next) +    mwAwareIdBlock_put(b, id_list->data); +} + + +static int send_add(struct mwChannel *chan, GList *id_list) { +  struct mwPutBuffer *b = mwPutBuffer_new(); +  struct mwOpaque o; +  int ret; + +  g_return_val_if_fail(chan != NULL, 0); + +  compose_list(b, id_list); + +  mwPutBuffer_finalize(&o, b); + +  ret = mwChannel_send(chan, msg_AWARE_ADD, &o); +  mwOpaque_clear(&o); + +  return ret;   +} + + +static int send_rem(struct mwChannel *chan, GList *id_list) { +  struct mwPutBuffer *b = mwPutBuffer_new(); +  struct mwOpaque o; +  int ret; + +  g_return_val_if_fail(chan != NULL, 0); + +  compose_list(b, id_list); +  mwPutBuffer_finalize(&o, b); + +  ret = mwChannel_send(chan, msg_AWARE_REMOVE, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +static gboolean collect_dead(gpointer key, gpointer val, gpointer data) { +  struct aware_entry *aware = val; +  GList **dead = data; + +  if(aware->membership == NULL) { +    // Miranda NG adaptation +    //g_info(" removing %s, %s", +	//   NSTR(aware->aware.id.user), NSTR(aware->aware.id.community)); +    g_message(" removing %s, %s", NSTR(aware->aware.id.user), NSTR(aware->aware.id.community)); +    *dead = g_list_append(*dead, aware); +    return TRUE; + +  } else { +    return FALSE; +  } +} + + +static int remove_unused(struct mwServiceAware *srvc) { +  /* - create a GList of all the unused aware entries +     - remove each unused aware from the service +     - if the service is alive, send a removal message for the collected +     unused. +  */ + +  int ret = 0; +  GList *dead = NULL, *l; + +  if(srvc->entries) { +    // Miranda NG adaptation +    //g_info("bring out your dead *clang*"); +    g_message("bring out your dead *clang*"); +    g_hash_table_foreach_steal(srvc->entries, collect_dead, &dead); +  } +  +  if(dead) { +    if(MW_SERVICE_IS_LIVE(srvc)) +      ret = send_rem(srvc->channel, dead) || ret; +     +    for(l = dead; l; l = l->next) +      aware_entry_free(l->data); + +    g_list_free(dead); +  } + +  return ret; +} + + +static int send_attrib_list(struct mwServiceAware *srvc) { +  struct mwPutBuffer *b; +  struct mwOpaque o; + +  int tmp; +  GList *l; + +  g_return_val_if_fail(srvc != NULL, -1); +  g_return_val_if_fail(srvc->channel != NULL, 0); + +  l = map_collect_keys(srvc->attribs); +  tmp = g_list_length(l); + +  b = mwPutBuffer_new(); +  guint32_put(b, 0x00); +  guint32_put(b, tmp); +   +  for(; l; l = g_list_delete_link(l, l)) { +    guint32_put(b, GPOINTER_TO_UINT(l->data)); +  } + +  mwPutBuffer_finalize(&o, b); +  tmp = mwChannel_send(srvc->channel, msg_OPT_WATCH, &o); +  mwOpaque_clear(&o); + +  return tmp; +} + + +static gboolean collect_attrib_dead(gpointer key, gpointer val, +				    gpointer data) { + +  struct attrib_entry *attrib = val; +  GList **dead = data; + +  if(attrib->membership == NULL) { +    // Miranda NG adaptation +    //g_info(" removing 0x%08x", GPOINTER_TO_UINT(key)); +    g_message(" removing 0x%08x", GPOINTER_TO_UINT(key)); +    *dead = g_list_append(*dead, attrib); +    return TRUE; + +  } else { +    return FALSE; +  } +} + + +static int remove_unused_attrib(struct mwServiceAware *srvc) { +  GList *dead = NULL; + +  if(srvc->attribs) { +    // Miranda NG adaptation +    //g_info("collecting dead attributes"); +    g_message("collecting dead attributes"); +    g_hash_table_foreach_steal(srvc->attribs, collect_attrib_dead, &dead); +  } +  +  /* since we stole them, we'll have to clean 'em up manually */ +  for(; dead; dead = g_list_delete_link(dead, dead)) { +    attrib_entry_free(dead->data); +  } + +  return MW_SERVICE_IS_LIVE(srvc)? send_attrib_list(srvc): 0; +} + + +static void recv_accept(struct mwServiceAware *srvc, +			struct mwChannel *chan, +			struct mwMsgChannelAccept *msg) { + +  g_return_if_fail(srvc->channel != NULL); +  g_return_if_fail(srvc->channel == chan); + +  if(MW_SERVICE_IS_STARTING(MW_SERVICE(srvc))) { +    GList *list = NULL; + +    list = map_collect_values(srvc->entries); +    send_add(chan, list); +    g_list_free(list); + +    send_attrib_list(srvc); + +    mwService_started(MW_SERVICE(srvc)); + +  } else { +    mwChannel_destroy(chan, ERR_FAILURE, NULL); +  } +} + + +static void recv_destroy(struct mwServiceAware *srvc, +			 struct mwChannel *chan, +			 struct mwMsgChannelDestroy *msg) { + +  srvc->channel = NULL; +  mwService_stop(MW_SERVICE(srvc)); + +  /** @todo session sense service and mwService_start */ +} + + +/** called from SNAPSHOT_recv, UPDATE_recv, and +    mwServiceAware_setStatus */ +static void status_recv(struct mwServiceAware *srvc, +			struct mwAwareSnapshot *idb) { + +  struct aware_entry *aware; +  GList *l; + +  aware = aware_find(srvc, &idb->id); + +  if(! aware) { +    /* we don't deal with receiving status for something we're not +       monitoring, but it will happen sometimes, eg from manually set +       status */ +    return; +  } +   +  /* clear the existing status, then clone in the new status */ +  mwAwareSnapshot_clear(&aware->aware); +  mwAwareSnapshot_clone(&aware->aware, idb); +   +  /* trigger each of the entry's lists */ +  for(l = aware->membership; l; l = l->next) { +    struct mwAwareList *alist = l->data; +    struct mwAwareListHandler *handler = alist->handler; + +    if(handler && handler->on_aware) +      handler->on_aware(alist, idb); +  } +} + + +static void attrib_recv(struct mwServiceAware *srvc, +			struct mwAwareIdBlock *idb, +			struct mwAwareAttribute *attrib) { + +  struct aware_entry *aware; +  struct mwAwareAttribute *old_attrib = NULL; +  GList *l; +  guint32 key; +  gpointer k; + +  aware = aware_find(srvc, idb); +  g_return_if_fail(aware != NULL); + +  key = attrib->key; +  k = GUINT_TO_POINTER(key); + +  if(aware->attribs) +    old_attrib = g_hash_table_lookup(aware->attribs, k); + +  if(! old_attrib) { +    old_attrib = g_new0(struct mwAwareAttribute, 1); +    old_attrib->key = key; +    g_hash_table_insert(aware->attribs, k, old_attrib); +  } +   +  mwOpaque_clear(&old_attrib->data); +  mwOpaque_clone(&old_attrib->data, &attrib->data); +   +  for(l = aware->membership; l; l = l->next) { +    struct mwAwareList *list = l->data; +    struct mwAwareListHandler *h = list->handler; + +    if(h && h->on_attrib && +       list->attribs && g_hash_table_lookup(list->attribs, k)) + +      h->on_attrib(list, idb, old_attrib); +  } +} + + +static gboolean list_add(struct mwAwareList *list, +			 struct mwAwareIdBlock *id) { + +  struct mwServiceAware *srvc = list->service; +  struct aware_entry *aware; + +  g_return_val_if_fail(id->user != NULL, FALSE); +  g_return_val_if_fail(strlen(id->user) > 0, FALSE); + +  if(! list->entries) +    list->entries = g_hash_table_new((GHashFunc) mwAwareIdBlock_hash, +				     (GEqualFunc) mwAwareIdBlock_equal); + +  aware = list_aware_find(list, id); +  if(aware) return FALSE; + +  aware = aware_find(srvc, id); +  if(! aware) { +    aware = g_new0(struct aware_entry, 1); +    aware->attribs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, +					   (GDestroyNotify) attrib_free); +    mwAwareIdBlock_clone(ENTRY_KEY(aware), id); + +    g_hash_table_insert(srvc->entries, ENTRY_KEY(aware), aware); +  } + +  aware->membership = g_list_append(aware->membership, list); + +  g_hash_table_insert(list->entries, ENTRY_KEY(aware), aware); + +  return TRUE; +} + + +static void group_member_recv(struct mwServiceAware *srvc, +			      struct mwAwareSnapshot *idb) { +  /* @todo +     - look up group by id +     - find each list group belongs to +     - add user to lists +  */ + +  struct mwAwareIdBlock gsrch = { mwAware_GROUP, idb->group, NULL }; +  struct aware_entry *grp; +  GList *l, *m; + +  grp = aware_find(srvc, &gsrch); +  g_return_if_fail(grp != NULL); /* this could happen, with timing. */ + +  l = g_list_prepend(NULL, &idb->id); + +  for(m = grp->membership; m; m = m->next) { + +    /* if we just list_add, we won't receive updates for attributes, +       so annoyingly we have to turn around and send out an add aware +       message for each incoming group member */ + +    /* list_add(m->data, &idb->id); */ +    mwAwareList_addAware(m->data, l); +  } + +  g_list_free(l); +} + + +static void recv_SNAPSHOT(struct mwServiceAware *srvc, +			  struct mwGetBuffer *b) { + +  guint32 count; + +  struct mwAwareSnapshot *snap; +  snap = g_new0(struct mwAwareSnapshot, 1); + +  guint32_get(b, &count); + +  while(count--) { +    mwAwareSnapshot_get(b, snap); + +    if(mwGetBuffer_error(b)) { +      mwAwareSnapshot_clear(snap); +      break; +    } + +    if(snap->group) +      group_member_recv(srvc, snap); + +    status_recv(srvc, snap); +    mwAwareSnapshot_clear(snap); +  } + +  g_free(snap); +} + + +static void recv_UPDATE(struct mwServiceAware *srvc, +			struct mwGetBuffer *b) { + +  struct mwAwareSnapshot *snap; + +  snap = g_new0(struct mwAwareSnapshot, 1); +  mwAwareSnapshot_get(b, snap); + +  if(snap->group) +    group_member_recv(srvc, snap); + +  if(! mwGetBuffer_error(b)) +    status_recv(srvc, snap); + +  mwAwareSnapshot_clear(snap); +  g_free(snap); +} + + +static void recv_GROUP(struct mwServiceAware *srvc, +		       struct mwGetBuffer *b) { + +  struct mwAwareIdBlock idb = { 0, 0, 0 }; + +  /* really nothing to be done with this. The group should have +     already been added to the list and service, and is now simply +     awaiting a snapshot/update with users listed as belonging in said +     group. */ + +  mwAwareIdBlock_get(b, &idb); +  mwAwareIdBlock_clear(&idb); +} + + +static void recv_OPT_GOT_SET(struct mwServiceAware *srvc, +			     struct mwGetBuffer *b) { + +  struct mwAwareAttribute attrib; +  struct mwAwareIdBlock idb; +  guint32 junk, check; + +  guint32_get(b, &junk); +  mwAwareIdBlock_get(b, &idb); +  guint32_get(b, &junk); +  guint32_get(b, &check); +  guint32_get(b, &junk); +  guint32_get(b, &attrib.key); + +  if(check) { +    mwOpaque_get(b, &attrib.data); +  } else { +    attrib.data.len = 0; +    attrib.data.data = NULL; +  } + +  attrib_recv(srvc, &idb, &attrib); + +  mwAwareIdBlock_clear(&idb); +  mwOpaque_clear(&attrib.data); +} + + +static void recv_OPT_GOT_UNSET(struct mwServiceAware *srvc, +			       struct mwGetBuffer *b) { + +  struct mwAwareAttribute attrib; +  struct mwAwareIdBlock idb; +  guint32 junk; + +  attrib.key = 0; +  attrib.data.len = 0; +  attrib.data.data = NULL; + +  guint32_get(b, &junk); +  mwAwareIdBlock_get(b, &idb); +  guint32_get(b, &attrib.key); + +  attrib_recv(srvc, &idb, &attrib); + +  mwAwareIdBlock_clear(&idb); +} + + +static void recv(struct mwService *srvc, struct mwChannel *chan, +		 guint16 type, struct mwOpaque *data) { + +  struct mwServiceAware *srvc_aware = (struct mwServiceAware *) srvc; +  struct mwGetBuffer *b; + +  g_return_if_fail(srvc_aware->channel == chan); +  g_return_if_fail(srvc->session == mwChannel_getSession(chan)); +  g_return_if_fail(data != NULL); + +  b = mwGetBuffer_wrap(data); + +  switch(type) { +  case msg_AWARE_SNAPSHOT: +    recv_SNAPSHOT(srvc_aware, b); +    break; + +  case msg_AWARE_UPDATE: +    recv_UPDATE(srvc_aware, b); +    break; + +  case msg_AWARE_GROUP: +    recv_GROUP(srvc_aware, b); +    break; + +  case msg_OPT_GOT_SET: +    recv_OPT_GOT_SET(srvc_aware, b); +    break; + +  case msg_OPT_GOT_UNSET: +    recv_OPT_GOT_UNSET(srvc_aware, b); +    break; + +  case msg_OPT_GOT_UNKNOWN: +  case msg_OPT_DID_SET: +  case msg_OPT_DID_UNSET: +  case msg_OPT_DID_ERROR: +    break; + +  default: +    mw_mailme_opaque(data, "unknown message in aware service: 0x%04x", type); +  } + +  mwGetBuffer_free(b);   +} + + +static void clear(struct mwService *srvc) { +  struct mwServiceAware *srvc_aware = (struct mwServiceAware *) srvc; + +  g_return_if_fail(srvc != NULL); + +  while(srvc_aware->lists) +    mwAwareList_free( (struct mwAwareList *) srvc_aware->lists->data ); + +  g_hash_table_destroy(srvc_aware->entries); +  srvc_aware->entries = NULL; + +  g_hash_table_destroy(srvc_aware->attribs); +  srvc_aware->attribs = NULL; +} + + +static const char *name(struct mwService *srvc) { +  return "Presence Awareness"; +} + + +static const char *desc(struct mwService *srvc) { +  return "Buddy list service with support for server-side groups"; +} + + +static struct mwChannel *make_blist(struct mwServiceAware *srvc, +				    struct mwChannelSet *cs) { + +  struct mwChannel *chan = mwChannel_newOutgoing(cs); + +  mwChannel_setService(chan, MW_SERVICE(srvc)); +  mwChannel_setProtoType(chan, 0x00000011); +  mwChannel_setProtoVer(chan, 0x00030005); + +  return mwChannel_create(chan)? NULL: chan; +} + + +static void start(struct mwService *srvc) { +  struct mwServiceAware *srvc_aware; +  struct mwChannel *chan = NULL; + +  srvc_aware = (struct mwServiceAware *) srvc; +  chan = make_blist(srvc_aware, mwSession_getChannels(srvc->session)); + +  if(chan != NULL) { +    srvc_aware->channel = chan; +  } else { +    mwService_stopped(srvc); +  } +} + + +static void stop(struct mwService *srvc) { +  struct mwServiceAware *srvc_aware; + +  srvc_aware = (struct mwServiceAware *) srvc; + +  if(srvc_aware->channel) { +    mwChannel_destroy(srvc_aware->channel, ERR_SUCCESS, NULL); +    srvc_aware->channel = NULL; +  } + +  mwService_stopped(srvc); +} + + +struct mwServiceAware * +mwServiceAware_new(struct mwSession *session, +		   struct mwAwareHandler *handler) { + +  struct mwService *service; +  struct mwServiceAware *srvc; + +  g_return_val_if_fail(session != NULL, NULL); +  g_return_val_if_fail(handler != NULL, NULL); + +  srvc = g_new0(struct mwServiceAware, 1); +  srvc->handler = handler; +  srvc->entries = g_hash_table_new_full((GHashFunc) mwAwareIdBlock_hash, +					(GEqualFunc) mwAwareIdBlock_equal, +					NULL, +					(GDestroyNotify) aware_entry_free); + +  srvc->attribs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, +					(GDestroyNotify) attrib_entry_free); + +  service = MW_SERVICE(srvc); +  mwService_init(service, session, mwService_AWARE); + +  service->recv_accept = (mwService_funcRecvAccept) recv_accept; +  service->recv_destroy = (mwService_funcRecvDestroy) recv_destroy; +  service->recv = recv; +  service->start = start; +  service->stop = stop; +  service->clear = clear; +  service->get_name = name; +  service->get_desc = desc; + +  return srvc; +} + + +int mwServiceAware_setAttribute(struct mwServiceAware *srvc, +				guint32 key, struct mwOpaque *data) { +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret; + +  b = mwPutBuffer_new(); + +  guint32_put(b, 0x00); +  guint32_put(b, data->len); +  guint32_put(b, 0x00); +  guint32_put(b, key); +  mwOpaque_put(b, data); + +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_send(srvc->channel, msg_OPT_DO_SET, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +int mwServiceAware_setAttributeBoolean(struct mwServiceAware *srvc, +				       guint32 key, gboolean val) { +  int ret; +  struct mwPutBuffer *b; +  struct mwOpaque o; +  +  b = mwPutBuffer_new(); + +  gboolean_put(b, FALSE); +  gboolean_put(b, val); + +  mwPutBuffer_finalize(&o, b); + +  ret = mwServiceAware_setAttribute(srvc, key, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +int mwServiceAware_setAttributeInteger(struct mwServiceAware *srvc, +				       guint32 key, guint32 val) { +  int ret; +  struct mwPutBuffer *b; +  struct mwOpaque o; +   +  b = mwPutBuffer_new(); +  guint32_put(b, val); + +  mwPutBuffer_finalize(&o, b); + +  ret = mwServiceAware_setAttribute(srvc, key, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +int mwServiceAware_setAttributeString(struct mwServiceAware *srvc, +				      guint32 key, const char *str) { +  int ret; +  struct mwPutBuffer *b; +  struct mwOpaque o; + +  b = mwPutBuffer_new(); +  mwString_put(b, str); + +  mwPutBuffer_finalize(&o, b); + +  ret = mwServiceAware_setAttribute(srvc, key, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +int mwServiceAware_unsetAttribute(struct mwServiceAware *srvc, +				  guint32 key) { +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret; + +  b = mwPutBuffer_new(); + +  guint32_put(b, 0x00); +  guint32_put(b, key); +   +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_send(srvc->channel, msg_OPT_DO_UNSET, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +guint32 mwAwareAttribute_getKey(const struct mwAwareAttribute *attrib) { +  g_return_val_if_fail(attrib != NULL, 0x00); +  return attrib->key; +} + + +gboolean mwAwareAttribute_asBoolean(const struct mwAwareAttribute *attrib) { +  struct mwGetBuffer *b; +  gboolean ret; +   +  if(! attrib) return FALSE; + +  b = mwGetBuffer_wrap(&attrib->data); +  if(attrib->data.len >= 4) { +    guint32 r32 = 0x00; +    guint32_get(b, &r32); +    ret = !! r32; + +  } else if(attrib->data.len >= 2) { +    guint16 r16 = 0x00; +    guint16_get(b, &r16); +    ret = !! r16; + +  } else if(attrib->data.len) { +    gboolean_get(b, &ret); +  } + +  mwGetBuffer_free(b); + +  return ret; +} + + +guint32 mwAwareAttribute_asInteger(const struct mwAwareAttribute *attrib) { +  struct mwGetBuffer *b; +  guint32 r32 = 0x00; +   +  if(! attrib) return 0x00; + +  b = mwGetBuffer_wrap(&attrib->data); +  if(attrib->data.len >= 4) { +    guint32_get(b, &r32); + +  } else if(attrib->data.len == 3) { +    gboolean rb = FALSE; +    guint16 r16 = 0x00; +    gboolean_get(b, &rb); +    guint16_get(b, &r16); +    r32 = (guint32) r16; + +  } else if(attrib->data.len == 2) { +    guint16 r16 = 0x00; +    guint16_get(b, &r16); +    r32 = (guint32) r16; + +  } else if(attrib->data.len) { +    gboolean rb = FALSE; +    gboolean_get(b, &rb); +    r32 = (guint32) rb; +  } + +  mwGetBuffer_free(b); + +  return r32; +} + + +char *mwAwareAttribute_asString(const struct mwAwareAttribute *attrib) { +  struct mwGetBuffer *b; +  char *ret = NULL; + +  if(! attrib) return NULL; + +  b = mwGetBuffer_wrap(&attrib->data); +  mwString_get(b, &ret); +  mwGetBuffer_free(b); + +  return ret; +} + + +const struct mwOpaque * +mwAwareAttribute_asOpaque(const struct mwAwareAttribute *attrib) { +  g_return_val_if_fail(attrib != NULL, NULL); +  return &attrib->data; +} +			   + +struct mwAwareList * +mwAwareList_new(struct mwServiceAware *srvc, +		struct mwAwareListHandler *handler) { + +  struct mwAwareList *al; + +  g_return_val_if_fail(srvc != NULL, NULL); +  g_return_val_if_fail(handler != NULL, NULL); + +  al = g_new0(struct mwAwareList, 1); +  al->service = srvc; +  al->handler = handler; + +  srvc->lists = g_list_prepend(srvc->lists, al); + +  return al; +} + + +void mwAwareList_free(struct mwAwareList *list) { +  struct mwServiceAware *srvc; +  struct mwAwareListHandler *handler; + +  g_return_if_fail(list != NULL); +  g_return_if_fail(list->service != NULL); + +  srvc = list->service; +  srvc->lists = g_list_remove_all(srvc->lists, list); + +  handler = list->handler; +  if(handler && handler->clear) { +    handler->clear(list); +    list->handler = NULL; +  } + +  mw_datum_clear(&list->client_data); + +  mwAwareList_unwatchAllAttributes(list); +  mwAwareList_removeAllAware(list); + +  list->service = NULL; + +  g_free(list); +} + + +struct mwAwareListHandler *mwAwareList_getHandler(struct mwAwareList *list) { +  g_return_val_if_fail(list != NULL, NULL); +  return list->handler; +} + + +/// Miranda NG adaptation start - new method +struct mwServiceAware *mwAwareList_getServiceAware(struct mwAwareList *list) { +  g_return_val_if_fail(list != NULL, NULL); +  return list->service; +} +/// Miranda NG adaptation end + + +static void watch_add(struct mwAwareList *list, guint32 key) { +  struct mwServiceAware *srvc; +  struct attrib_entry *watch; +  gpointer k = GUINT_TO_POINTER(key); + +  if(! list->attribs) +    list->attribs = g_hash_table_new(g_direct_hash, g_direct_equal); + +  if(g_hash_table_lookup(list->attribs, k)) +    return; + +  srvc = list->service; + +  watch = g_hash_table_lookup(srvc->attribs, k); +  if(! watch) { +    watch = g_new0(struct attrib_entry, 1); +    watch->key = key; +    g_hash_table_insert(srvc->attribs, k, watch); +  } + +  g_hash_table_insert(list->attribs, k, watch); + +  watch->membership = g_list_prepend(watch->membership, list); +} + + +static void watch_remove(struct mwAwareList *list, guint32 key) { +  struct attrib_entry *watch = NULL; +  gpointer k = GUINT_TO_POINTER(key); + +  if(list->attribs) +    watch = g_hash_table_lookup(list->attribs, k); + +  g_return_if_fail(watch != NULL); + +  g_hash_table_remove(list->attribs, k); +  watch->membership = g_list_remove(watch->membership, list); +} + + +int mwAwareList_watchAttributeArray(struct mwAwareList *list, +				    guint32 *keys) { +  guint32 k; + +  g_return_val_if_fail(list != NULL, -1); +  g_return_val_if_fail(list->service != NULL, -1); + +  if(! keys) return 0; + +  for(k = *keys; k; keys++) +    watch_add(list, k); + +  return send_attrib_list(list->service); +} + + +int mwAwareList_watchAttributes(struct mwAwareList *list, +				guint32 key, ...) { +  guint32 k; +  va_list args; + +  g_return_val_if_fail(list != NULL, -1); +  g_return_val_if_fail(list->service != NULL, -1); + +  va_start(args, key); +  for(k = key; k; k = va_arg(args, guint32)) +    watch_add(list, k); +  va_end(args); + +  return send_attrib_list(list->service); +} + + +int mwAwareList_unwatchAttributeArray(struct mwAwareList *list, +				      guint32 *keys) { +  guint32 k; + +  g_return_val_if_fail(list != NULL, -1); +  g_return_val_if_fail(list->service != NULL, -1); + +  if(! keys) return 0; + +  for(k = *keys; k; keys++) +    watch_add(list, k); + +  return remove_unused_attrib(list->service); +} + + +int mwAwareList_unwatchAttributes(struct mwAwareList *list, +				  guint32 key, ...) { +  guint32 k; +  va_list args; + +  g_return_val_if_fail(list != NULL, -1); +  g_return_val_if_fail(list->service != NULL, -1); + +  va_start(args, key); +  for(k = key; k; k = va_arg(args, guint32)) +    watch_remove(list, k); +  va_end(args); + +  return remove_unused_attrib(list->service); +} + + +static void dismember_attrib(gpointer k, struct attrib_entry *watch, +			    struct mwAwareList *list) { + +  watch->membership = g_list_remove(watch->membership, list); +} + + +int mwAwareList_unwatchAllAttributes(struct mwAwareList *list) { +   +  struct mwServiceAware *srvc; + +  g_return_val_if_fail(list != NULL, -1); +  srvc = list->service; + +  if(list->attribs) { +    g_hash_table_foreach(list->attribs, (GHFunc) dismember_attrib, list); +    g_hash_table_destroy(list->attribs); +  } + +  return remove_unused_attrib(srvc); +} + + +static void collect_attrib_keys(gpointer key, struct attrib_entry *attrib, +				guint32 **ck) { +  guint32 *keys = (*ck)++; +  *keys = GPOINTER_TO_UINT(key); +} + + +guint32 *mwAwareList_getWatchedAttributes(struct mwAwareList *list) { +  guint32 *keys, **ck; +  guint count; + +  g_return_val_if_fail(list != NULL, NULL); +  g_return_val_if_fail(list->attribs != NULL, NULL); +   +  count = g_hash_table_size(list->attribs); +  keys = g_new0(guint32, count + 1); + +  ck = &keys; +  g_hash_table_foreach(list->attribs, (GHFunc) collect_attrib_keys, ck); + +  return keys; +} + + +int mwAwareList_addAware(struct mwAwareList *list, GList *id_list) { + +  /* for each awareness id: +     - if it's already in the list, continue +     - if it's not in the service list: +       - create an awareness +       - add it to the service list +     - add this list to the membership +     - add to the list +  */ + +  struct mwServiceAware *srvc; +  GList *additions = NULL; +  int ret = 0; + +  g_return_val_if_fail(list != NULL, -1); + +  srvc = list->service; +  g_return_val_if_fail(srvc != NULL, -1); + +  for(; id_list; id_list = id_list->next) { +    if(list_add(list, id_list->data)) +      additions = g_list_prepend(additions, id_list->data); +  } + +  /* if the service is alive-- or getting there-- we'll need to send +     these additions upstream */ +  if(MW_SERVICE_IS_LIVE(srvc) && additions) +    ret = send_add(srvc->channel, additions); + +  g_list_free(additions); +  return ret; +} + + +int mwAwareList_removeAware(struct mwAwareList *list, GList *id_list) { + +  /* for each awareness id: +     - if it's not in the list, forget it +     - remove from the list +     - remove list from the membership + +     - call remove round +  */ + +  struct mwServiceAware *srvc; +  struct mwAwareIdBlock *id; +  struct aware_entry *aware; + +  g_return_val_if_fail(list != NULL, -1); + +  srvc = list->service; +  g_return_val_if_fail(srvc != NULL, -1); + +  for(; id_list; id_list = id_list->next) { +    id = id_list->data; +    aware = list_aware_find(list, id); + +    if(! aware) { +      g_warning("buddy %s, %s not in list", +		NSTR(id->user), +		NSTR(id->community)); +      continue; +    } + +    aware->membership = g_list_remove(aware->membership, list); +    g_hash_table_remove(list->entries, id); +  } + +  return remove_unused(srvc); +} + + +static void dismember_aware(gpointer k, struct aware_entry *aware, +			    struct mwAwareList *list) { + +  aware->membership = g_list_remove(aware->membership, list); +} + + +int mwAwareList_removeAllAware(struct mwAwareList *list) { +  struct mwServiceAware *srvc; + +  g_return_val_if_fail(list != NULL, -1); +  srvc = list->service; + +  g_return_val_if_fail(srvc != NULL, -1); + +  /* for each entry, remove the aware list from the service entry's +     membership collection */ +  if(list->entries) { +    g_hash_table_foreach(list->entries, (GHFunc) dismember_aware, list); +    g_hash_table_destroy(list->entries); +  } + +  return remove_unused(srvc); +} + + +void mwAwareList_setClientData(struct mwAwareList *list, +			       gpointer data, GDestroyNotify clear) { + +  g_return_if_fail(list != NULL); +  mw_datum_set(&list->client_data, data, clear); +} + + +gpointer mwAwareList_getClientData(struct mwAwareList *list) { +  g_return_val_if_fail(list != NULL, NULL); +  return mw_datum_get(&list->client_data); +} + + +void mwAwareList_removeClientData(struct mwAwareList *list) { +  g_return_if_fail(list != NULL); +  mw_datum_clear(&list->client_data); +} + + +void mwServiceAware_setStatus(struct mwServiceAware *srvc, +			      struct mwAwareIdBlock *user, +			      struct mwUserStatus *stat) { + +  struct mwAwareSnapshot idb; + +  g_return_if_fail(srvc != NULL); +  g_return_if_fail(user != NULL); +  g_return_if_fail(stat != NULL); + +  /* just reference the strings. then we don't need to free them */ +  idb.id.type = user->type; +  idb.id.user = user->user; +  idb.id.community = user->community; + +  idb.group = NULL; +  idb.online = TRUE; +  idb.alt_id = NULL; + +  idb.status.status = stat->status; +  idb.status.time = stat->time; +  idb.status.desc = stat->desc; + +  idb.name = NULL; + +  status_recv(srvc, &idb); +} + + +const struct mwAwareAttribute * +mwServiceAware_getAttribute(struct mwServiceAware *srvc, +			    struct mwAwareIdBlock *user, +			    guint32 key) { + +  struct aware_entry *aware; + +  g_return_val_if_fail(srvc != NULL, NULL); +  g_return_val_if_fail(user != NULL, NULL); +  g_return_val_if_fail(key != 0x00, NULL); + +  aware = aware_find(srvc, user); +  g_return_val_if_fail(aware != NULL, NULL); + +  return g_hash_table_lookup(aware->attribs, GUINT_TO_POINTER(key)); +} + + +const char *mwServiceAware_getText(struct mwServiceAware *srvc, +				   struct mwAwareIdBlock *user) { + +  struct aware_entry *aware; + +  g_return_val_if_fail(srvc != NULL, NULL); +  g_return_val_if_fail(user != NULL, NULL); + +  aware = aware_find(srvc, user); +  if(! aware) return NULL; + +  return aware->aware.status.desc; +} + + +/// Miranda NG adaptation start - new method +struct mwService *mwServiceAware_getService(struct mwServiceAware *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return &(srvc->service); +} +/// Miranda NG adaptation end diff --git a/protocols/Sametime/src/meanwhile/src/srvc_conf.c b/protocols/Sametime/src/meanwhile/src/srvc_conf.c new file mode 100644 index 0000000000..f302a706f8 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/srvc_conf.c @@ -0,0 +1,884 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <glib.h> +#include <glib/ghash.h> +#include <glib/glist.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "mw_channel.h" +#include "mw_debug.h" +#include "mw_error.h" +#include "mw_message.h" +#include "mw_service.h" +#include "mw_session.h" +#include "mw_srvc_conf.h" +#include "mw_util.h" + + +/* This thing needs a re-write. More than anything else, I need to +   re-examine the conferencing service protocol from more modern +   clients */ + + +#define PROTOCOL_TYPE   0x00000010 +#define PROTOCOL_VER    0x00000002 + + +/** @see mwMsgChannelSend::type +    @see recv */ +enum msg_type { +  msg_WELCOME  = 0x0000,  /**< welcome message */ +  msg_INVITE   = 0x0001,  /**< outgoing invitation */ +  msg_JOIN     = 0x0002,  /**< someone joined */ +  msg_PART     = 0x0003,  /**< someone left */ +  msg_MESSAGE  = 0x0004,  /**< conference message */ +}; + + +/** the conferencing service */ +struct mwServiceConference { +  struct mwService service; + +  /** call-back handler for this service */ +  struct mwConferenceHandler *handler; + +  /** collection of conferences in this service */ +  GList *confs; +}; + + +/** a conference and its members */ +struct mwConference { +  enum mwConferenceState state;   /**< state of the conference */ +  struct mwServiceConference *service;  /**< owning service */ +  struct mwChannel *channel;      /**< conference's channel */ + +  char *name;   /**< server identifier for the conference */ +  char *title;  /**< topic for the conference */ + +  struct mwLoginInfo owner;  /**< person who created this conference */ +  GHashTable *members;       /**< mapping guint16:mwLoginInfo */ +  struct mw_datum client_data; +}; + + +#define MEMBER_FIND(conf, id) \ +  g_hash_table_lookup(conf->members, GUINT_TO_POINTER((guint) id)) + + +#define MEMBER_ADD(conf, id, member) \ +  g_hash_table_insert(conf->members, GUINT_TO_POINTER((guint) id), member) + + +#define MEMBER_REM(conf, id) \ +  g_hash_table_remove(conf->members, GUINT_TO_POINTER((guint) id)); + + +/** clear and free a login info block */ +static void login_free(struct mwLoginInfo *li) { +  mwLoginInfo_clear(li); +  g_free(li); +} + + +/** generates a random conference name built around a user name */ +static char *conf_generate_name(const char *user) { +  /// Miranda NG adaptation start - MSVC +  ///guint a, b; +  guint a; +  guint64 b; +  /// Miranda NG adaptation end +  char *ret; +   +  user = user? user: ""; + +  srand(clock() + rand()); +  a = ((rand() & 0xff) << 8) | (rand() & 0xff); +  b = time(NULL); + +  /// Miranda NG adaptation start - MSVC +  ///ret = g_strdup_printf("%s(%08x,%04x)", user, b, a); +  ret = g_strdup_printf("%s(%I64u,%04x)", user, b, a); +  /// Miranda NG adaptation end +  g_debug("generated random conference name: '%s'", ret); +  return ret; +} + + + + + +static struct mwConference *conf_new(struct mwServiceConference *srvc) { + +  struct mwConference *conf; +  struct mwSession *session; +  const char *user; + +  conf = g_new0(struct mwConference, 1); +  conf->state = mwConference_NEW; +  conf->service = srvc; +  conf->members = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, +					(GDestroyNotify) login_free); + +  session = mwService_getSession(MW_SERVICE(srvc)); +  user = mwSession_getProperty(session, mwSession_AUTH_USER_ID); + +  srvc->confs = g_list_prepend(srvc->confs, conf); + +  return conf; +} + + +/** clean and free a conference structure */ +static void conf_free(struct mwConference *conf) { +  struct mwServiceConference *srvc; + +  /* this shouldn't ever happen, but just to be sure */ +  g_return_if_fail(conf != NULL); +   +  srvc = conf->service; + +  if(conf->members) +    g_hash_table_destroy(conf->members); + +  g_list_remove_all(srvc->confs, conf); + +  mw_datum_clear(&conf->client_data); +   +  g_free(conf->name); +  g_free(conf->title); +  g_free(conf); +} + + +static struct mwConference *conf_find(struct mwServiceConference *srvc, +				      struct mwChannel *chan) { +  GList *l; + +  g_return_val_if_fail(srvc != NULL, NULL); +  g_return_val_if_fail(chan != NULL, NULL); +   +  for(l = srvc->confs; l; l = l->next) { +    struct mwConference *conf = l->data; +    if(conf->channel == chan) return conf; +  } + +  return NULL; +} + + +static const char *conf_state_str(enum mwConferenceState state) { +  switch(state) { +  case mwConference_NEW:      return "new"; +  case mwConference_PENDING:  return "pending"; +  case mwConference_INVITED:  return "invited"; +  case mwConference_OPEN:     return "open"; +  case mwConference_CLOSING:  return "closing"; +  case mwConference_ERROR:    return "error"; + +  case mwConference_UNKNOWN:  /* fall through */ +  default:                    return "UNKNOWN"; +  } +} + + +static void conf_state(struct mwConference *conf, +		       enum mwConferenceState state) { +  g_return_if_fail(conf != NULL); + +  if(conf->state == state) return; + +  conf->state = state; +  g_message("conference %s state: %s", +	    NSTR(conf->name), conf_state_str(state)); +} + + +static void recv_channelCreate(struct mwService *srvc, +			       struct mwChannel *chan, +			       struct mwMsgChannelCreate *msg) { + +  /* - this is how we really receive invitations +     - create a conference and associate it with the channel +     - obtain the invite data from the msg addtl info +     - mark the conference as INVITED +     - trigger the got_invite event +  */ + +  struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc; +  struct mwConference *conf; + +  struct mwGetBuffer *b; + +  char *invite = NULL; +  guint tmp; + +  conf = conf_new(srvc_conf); +  conf->channel = chan; + +  b = mwGetBuffer_wrap(&msg->addtl); + +  guint32_get(b, &tmp); +  mwString_get(b, &conf->name); +  mwString_get(b, &conf->title); +  guint32_get(b, &tmp); +  mwLoginInfo_get(b, &conf->owner); +  guint32_get(b, &tmp); +  mwString_get(b, &invite); + +  if(mwGetBuffer_error(b)) { +    g_warning("failure parsing addtl for conference invite"); +    mwConference_destroy(conf, ERR_FAILURE, NULL); + +  } else { +    struct mwConferenceHandler *h = srvc_conf->handler; +    conf_state(conf, mwConference_INVITED); +    if(h->on_invited) +      h->on_invited(conf, &conf->owner, invite); +  } + +  mwGetBuffer_free(b); +  g_free(invite); +} + + +static void recv_channelAccept(struct mwService *srvc, +			       struct mwChannel *chan, +			       struct mwMsgChannelAccept *msg) { + +  ; +} + + +static void recv_channelDestroy(struct mwService *srvc, +				struct mwChannel *chan, +				struct mwMsgChannelDestroy *msg) { + +  /* - find conference from channel +     - trigger got_closed +     - remove conference, dealloc +  */ + +  struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc; +  struct mwConference *conf = conf_find(srvc_conf, chan); +  struct mwConferenceHandler *h = srvc_conf->handler; + +  /* if there's no such conference, then I guess there's nothing to worry +     about. Except of course for the fact that we should never receive a +     channel destroy for a conference that doesn't exist. */ +  if(! conf) return; + +  conf->channel = NULL; + +  conf_state(conf, msg->reason? mwConference_ERROR: mwConference_CLOSING); + +  if(h->conf_closed) +    h->conf_closed(conf, msg->reason); + +  mwConference_destroy(conf, ERR_SUCCESS, NULL); +} + + +static void WELCOME_recv(struct mwServiceConference *srvc, +			 struct mwConference *conf, +			 struct mwGetBuffer *b) { + +  struct mwConferenceHandler *h; +  guint16 tmp16; +  guint32 tmp32; +  guint32 count; +  GList *l = NULL; + +  /* re-read name and title */ +  g_free(conf->name); +  g_free(conf->title); +  conf->name = NULL; +  conf->title = NULL; +  mwString_get(b, &conf->name); +  mwString_get(b, &conf->title); + +  /* some numbers we don't care about, then a count of members */ +  guint16_get(b, &tmp16); +  guint32_get(b, &tmp32); +  guint32_get(b, &count); + +  if(mwGetBuffer_error(b)) { +    g_warning("error parsing welcome message for conference"); +    mwConference_destroy(conf, ERR_FAILURE, NULL); +    return; +  } +   +  while(count--) { +    guint16 member_id; +    struct mwLoginInfo *member = g_new0(struct mwLoginInfo, 1); + +    guint16_get(b, &member_id); +    mwLoginInfo_get(b, member); + +    if(mwGetBuffer_error(b)) { +      login_free(member); +      break; +    } + +    MEMBER_ADD(conf, member_id, member); +    l = g_list_append(l, member); +  } + +  conf_state(conf, mwConference_OPEN); + +  h = srvc->handler; +  if(h->conf_opened) +    h->conf_opened(conf, l); + +  /* get rid of the GList, but not its contents */ +  g_list_free(l); +} + + +static void JOIN_recv(struct mwServiceConference *srvc, +		      struct mwConference *conf, +		      struct mwGetBuffer *b) { + +  struct mwConferenceHandler *h; +  guint16 m_id; +  struct mwLoginInfo *m; +   +  /* for some inane reason, conferences we create will send a join +     message for ourselves before the welcome message. Since the +     welcome message will list our ID among those in the channel, +     we're going to just pretend that these join messages don't +     exist */ +  if(conf->state == mwConference_PENDING) +    return; + +  m = g_new0(struct mwLoginInfo, 1); + +  guint16_get(b, &m_id); +  mwLoginInfo_get(b, m); + +  if(mwGetBuffer_error(b)) { +    g_warning("failed parsing JOIN message in conference"); +    login_free(m); +    return; +  } + +  MEMBER_ADD(conf, m_id, m); + +  h = srvc->handler; +  if(h->on_peer_joined) +    h->on_peer_joined(conf, m); +} + + +static void PART_recv(struct mwServiceConference *srvc, +		      struct mwConference *conf, +		      struct mwGetBuffer *b) { + +  /* - parse who left +     - look up their membership +     - remove them from the members list +     - trigger the event +  */ + +  struct mwConferenceHandler *h; +  guint16 id = 0; +  struct mwLoginInfo *m; + +  guint16_get(b, &id); + +  if(mwGetBuffer_error(b)) return; + +  m = MEMBER_FIND(conf, id); +  if(! m) return; + +  h = srvc->handler; +  if(h->on_peer_parted) +    h->on_peer_parted(conf, m); + +  MEMBER_REM(conf, id); +} + + +static void text_recv(struct mwServiceConference *srvc, +		      struct mwConference *conf, +		      struct mwLoginInfo *m, +		      struct mwGetBuffer *b) { + +  /* this function acts a lot like receiving an IM Text message. The text +     message contains only a string */ + +  char *text = NULL; +  struct mwConferenceHandler *h; +   +  mwString_get(b, &text); + +  if(mwGetBuffer_error(b)) { +    g_warning("failed to parse text message in conference"); +    g_free(text); +    return; +  } + +  h = srvc->handler; +  if(text && h->on_text) { +    h->on_text(conf, m, text); +  } + +  g_free(text); +} + + +static void data_recv(struct mwServiceConference *srvc, +		      struct mwConference *conf, +		      struct mwLoginInfo *m, +		      struct mwGetBuffer *b) { + +  /* this function acts a lot like receiving an IM Data message. The +     data message has a type, a subtype, and an opaque. We only +     support typing notification though. */ + +  /** @todo it's possible that some clients send text in a data +      message, as we've seen rarely in the IM service. Have to add +      support for that here */ + +  guint32 type, subtype; +  struct mwConferenceHandler *h; + +  guint32_get(b, &type); +  guint32_get(b, &subtype); + +  if(mwGetBuffer_error(b)) return; + +  /* don't know how to deal with any others yet */ +  if(type != 0x01) { +    g_message("unknown data message type (0x%08x, 0x%08x)", type, subtype); +    return; +  } + +  h = srvc->handler; +  if(h->on_typing) { +    h->on_typing(conf, m, !subtype); +  } +} + + +static void MESSAGE_recv(struct mwServiceConference *srvc, +			 struct mwConference *conf, +			 struct mwGetBuffer *b) { + +  /* - look up who send the message by their id +     - trigger the event +  */ + +  guint16 id; +  guint32 type; +  struct mwLoginInfo *m; + +  /* an empty buffer isn't an error, just ignored */ +  if(! mwGetBuffer_remaining(b)) return; + +  guint16_get(b, &id); +  guint32_get(b, &type); /* reuse type variable */ +  guint32_get(b, &type); + +  if(mwGetBuffer_error(b)) return; + +  m = MEMBER_FIND(conf, id); +  if(! m) { +    g_warning("received message type 0x%04x from" +	      " unknown conference member %u", type, id); +    return; +  } +   +  switch(type) { +  case 0x01:  /* type is text */ +    text_recv(srvc, conf, m, b); +    break; + +  case 0x02:  /* type is data */ +    data_recv(srvc, conf, m, b); +    break; + +  default: +    g_warning("unknown message type 0x%4x received in conference", type); +  } +} + + +static void recv(struct mwService *srvc, struct mwChannel *chan, +		 guint16 type, struct mwOpaque *data) { + +  struct mwServiceConference *srvc_conf = (struct mwServiceConference *) srvc; +  struct mwConference *conf = conf_find(srvc_conf, chan); +  struct mwGetBuffer *b; + +  g_return_if_fail(conf != NULL); + +  b = mwGetBuffer_wrap(data); + +  switch(type) { +  case msg_WELCOME: +    WELCOME_recv(srvc_conf, conf, b); +    break; + +  case msg_JOIN: +    JOIN_recv(srvc_conf, conf, b); +    break; + +  case msg_PART: +    PART_recv(srvc_conf, conf, b); +    break; + +  case msg_MESSAGE: +    MESSAGE_recv(srvc_conf, conf, b); +    break; + +  default: +    ; /* hrm. should log this. TODO */ +  } +} + + +static void clear(struct mwServiceConference *srvc) { +  struct mwConferenceHandler *h; + +  while(srvc->confs) +    conf_free(srvc->confs->data); + +  h = srvc->handler; +  if(h && h->clear) +    h->clear(srvc); +  srvc->handler = NULL; +} + + +static const char *name(struct mwService *srvc) { +  return "Basic Conferencing"; +} + + +static const char *desc(struct mwService *srvc) { +  return "Multi-user plain-text conferencing"; +} + + +static void start(struct mwService *srvc) { +  mwService_started(srvc); +} + + +static void stop(struct mwServiceConference *srvc) { +  while(srvc->confs) +    mwConference_destroy(srvc->confs->data, ERR_SUCCESS, NULL); + +  mwService_stopped(MW_SERVICE(srvc)); +} + + +struct mwServiceConference * +mwServiceConference_new(struct mwSession *session, +			struct mwConferenceHandler *handler) { + +  struct mwServiceConference *srvc_conf; +  struct mwService *srvc; + +  g_return_val_if_fail(session != NULL, NULL); +  g_return_val_if_fail(handler != NULL, NULL); + +  srvc_conf = g_new0(struct mwServiceConference, 1); +  srvc = &srvc_conf->service; + +  mwService_init(srvc, session, mwService_CONFERENCE); +  srvc->start = start; +  srvc->stop = (mwService_funcStop) stop; +  srvc->recv_create = recv_channelCreate; +  srvc->recv_accept = recv_channelAccept; +  srvc->recv_destroy = recv_channelDestroy; +  srvc->recv = recv; +  srvc->clear = (mwService_funcClear) clear; +  srvc->get_name = name; +  srvc->get_desc = desc; + +  srvc_conf->handler = handler; + +  return srvc_conf; +} + + +struct mwConference *mwConference_new(struct mwServiceConference *srvc, +				      const char *title) { +  struct mwConference *conf; + +  g_return_val_if_fail(srvc != NULL, NULL); + +  conf = conf_new(srvc); +  conf->title = g_strdup(title); + +  return conf; +} + + +/// Miranda NG adaptation start - renamed method +struct mwServiceConference * +mwConference_getServiceConference(struct mwConference *conf) { +  g_return_val_if_fail(conf != NULL, NULL); +  return conf->service; +} +/// Miranda NG adaptation end + + +/// Miranda NG adaptation start - new method +struct mwService *mwServiceConference_getService(struct mwServiceConference *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return &(srvc->service); +} +/// Miranda NG adaptation end + + +const char *mwConference_getName(struct mwConference *conf) { +  g_return_val_if_fail(conf != NULL, NULL); +  return conf->name; +} + + +const char *mwConference_getTitle(struct mwConference *conf) { +  g_return_val_if_fail(conf != NULL, NULL); +  return conf->title; +} + + +GList *mwConference_getMembers(struct mwConference *conf) { +  g_return_val_if_fail(conf != NULL, NULL); +  g_return_val_if_fail(conf->members != NULL, NULL); + +  return map_collect_values(conf->members); +} + + +int mwConference_open(struct mwConference *conf) { +  struct mwSession *session; +  struct mwChannel *chan; +  struct mwPutBuffer *b; +  int ret; +   +  g_return_val_if_fail(conf != NULL, -1); +  g_return_val_if_fail(conf->service != NULL, -1); +  g_return_val_if_fail(conf->state == mwConference_NEW, -1); +  g_return_val_if_fail(conf->channel == NULL, -1); + +  session = mwService_getSession(MW_SERVICE(conf->service)); +  g_return_val_if_fail(session != NULL, -1); + +  if(! conf->name) { +    char *user = mwSession_getProperty(session, mwSession_AUTH_USER_ID); +    conf->name = conf_generate_name(user? user: "meanwhile"); +  } + +  chan = mwChannel_newOutgoing(mwSession_getChannels(session)); +  mwChannel_setService(chan, MW_SERVICE(conf->service)); +  mwChannel_setProtoType(chan, PROTOCOL_TYPE); +  mwChannel_setProtoVer(chan, PROTOCOL_VER); +   +#if 0 +  /* offer all known ciphers */ +  mwChannel_populateSupportedCipherInstances(chan); +#endif + +  b = mwPutBuffer_new(); +  mwString_put(b, conf->name); +  mwString_put(b, conf->title); +  guint32_put(b, 0x00); +  mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b); + +  ret = mwChannel_create(chan); +  if(ret) { +    conf_state(conf, mwConference_ERROR); +  } else { +    conf_state(conf, mwConference_PENDING); +    conf->channel = chan; +  } + +  return ret; +} + + +int mwConference_destroy(struct mwConference *conf, +			 guint32 reason, const char *text) { + +  struct mwServiceConference *srvc; +  struct mwOpaque info = { 0, 0 }; +  int ret = 0; + +  g_return_val_if_fail(conf != NULL, -1); + +  srvc = conf->service; +  g_return_val_if_fail(srvc != NULL, -1); + +  /* remove conference from the service */ +  srvc->confs = g_list_remove_all(srvc->confs, conf); + +  /* close the channel if applicable */ +  if(conf->channel) { +    if(text && *text) { +      info.len = strlen(text); +      info.data = (guchar *) text; +    } + +    ret = mwChannel_destroy(conf->channel, reason, &info); +  } +   +  /* free the conference */ +  conf_free(conf); + +  return ret; +} + + +int mwConference_accept(struct mwConference *conf) { +  /* - if conference is not INVITED, return -1 +     - accept the conference channel +     - send an empty JOIN message +  */ + +  struct mwChannel *chan; +  int ret; + +  g_return_val_if_fail(conf != NULL, -1); +  g_return_val_if_fail(conf->state == mwConference_INVITED, -1); + +  chan = conf->channel; +  ret = mwChannel_accept(chan); + +  if(! ret) +    ret = mwChannel_sendEncrypted(chan, msg_JOIN, NULL, FALSE); + +  return ret; +} + + +int mwConference_invite(struct mwConference *conf, +			struct mwIdBlock *who, +			const char *text) { + +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret; + +  g_return_val_if_fail(conf != NULL, -1); +  g_return_val_if_fail(conf->channel != NULL, -1); +  g_return_val_if_fail(who != NULL, -1); + +  b = mwPutBuffer_new(); + +  mwIdBlock_put(b, who); +  guint16_put(b, 0x00); +  guint32_put(b, 0x00); +  mwString_put(b, text); +  mwString_put(b, who->user); + +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_sendEncrypted(conf->channel, msg_INVITE, &o, FALSE); +  mwOpaque_clear(&o); + +  return ret; +} + + +int mwConference_sendText(struct mwConference *conf, const char *text) { +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret; + +  g_return_val_if_fail(conf != NULL, -1); +  g_return_val_if_fail(conf->channel != NULL, -1); + +  b = mwPutBuffer_new(); + +  guint32_put(b, 0x01); +  mwString_put(b, text); + +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_sendEncrypted(conf->channel, msg_MESSAGE, &o, FALSE); +  mwOpaque_clear(&o); + +  return ret; +} + + +int mwConference_sendTyping(struct mwConference *conf, gboolean typing) { +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret; + +  g_return_val_if_fail(conf != NULL, -1); +  g_return_val_if_fail(conf->channel != NULL, -1); +  g_return_val_if_fail(conf->state == mwConference_OPEN, -1); + +  b = mwPutBuffer_new(); + +  guint32_put(b, 0x02); +  guint32_put(b, 0x01); +  guint32_put(b, !typing); +  mwOpaque_put(b, NULL); + +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_sendEncrypted(conf->channel, msg_MESSAGE, &o, FALSE); +  mwOpaque_clear(&o); + +  return ret; +} + + +void mwConference_setClientData(struct mwConference *conference, +			     gpointer data, GDestroyNotify clear) { + +  g_return_if_fail(conference != NULL); +  mw_datum_set(&conference->client_data, data, clear); +} + + +gpointer mwConference_getClientData(struct mwConference *conference) { +  g_return_val_if_fail(conference != NULL, NULL); +  return mw_datum_get(&conference->client_data); +} + + +void mwConference_removeClientData(struct mwConference *conference) { +  g_return_if_fail(conference != NULL); +  mw_datum_clear(&conference->client_data); +} + + +struct mwConferenceHandler * +mwServiceConference_getHandler(struct mwServiceConference *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return srvc->handler; +} + + +GList *mwServiceConference_getConferences(struct mwServiceConference *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return g_list_copy(srvc->confs); +} + diff --git a/protocols/Sametime/src/meanwhile/src/srvc_dir.c b/protocols/Sametime/src/meanwhile/src/srvc_dir.c new file mode 100644 index 0000000000..1505f69c53 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/srvc_dir.c @@ -0,0 +1,664 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <glib/ghash.h> + +#include "mw_channel.h" +#include "mw_common.h" +#include "mw_debug.h" +#include "mw_error.h" +#include "mw_message.h" +#include "mw_service.h" +#include "mw_session.h" +#include "mw_srvc_dir.h" +#include "mw_util.h" + + +#define PROTOCOL_TYPE  0x0000001c +#define PROTOCOL_VER   0x00000005 + + +enum dir_action { +  action_list    = 0x0000,  /**< list address books */ +  action_open    = 0x0001,  /**< open an addressbook as a directory */ +  action_close   = 0x0002,  /**< close a directory */ +  action_search  = 0x0003,  /**< search an open directory */ +}; + + +struct mwServiceDirectory { +  struct mwService service; + +  struct mwDirectoryHandler *handler; + +  struct mwChannel *channel; +  +  guint32 counter;       /**< counter of request IDs */ +  GHashTable *requests;  /**< map of request ID:directory */ +  GHashTable *books;     /**< book->name:mwAddressBook */ +}; + + +struct mwAddressBook { +  struct mwServiceDirectory *service; + +  guint32 id;        /**< id or type or something */ +  char *name;        /**< name of address book */ +  GHashTable *dirs;  /**< dir->id:mwDirectory */ +}; + + +struct mwDirectory { +  struct mwServiceDirectory *service; +  struct mwAddressBook *book; + +  enum mwDirectoryState state; + +  guint32 id;         /**< id of directory, assigned by server */ +  guint32 search_id;  /**< id of current search, from srvc->counter++ */ + +  mwSearchHandler handler; +  struct mw_datum client_data; +}; + + +#define next_request_id(srvc) ( ++((srvc)->counter) ) + + +static guint32 map_request(struct mwDirectory *dir) { +  struct mwServiceDirectory *srvc = dir->service; +  guint32 id = next_request_id(srvc); + +  dir->search_id = id; +  map_guint_insert(srvc->requests, id, dir); + +  return id; +} + + +/** called when directory is removed from the service directory map */ +static void dir_free(struct mwDirectory *dir) { +  map_guint_remove(dir->service->requests, dir->search_id); +  g_free(dir); +} + + +/** remove the directory from the service list and its owning address +    book, then frees the directory */ +static void dir_remove(struct mwDirectory *dir) { +  struct mwAddressBook *book = dir->book; +  map_guint_remove(book->dirs, dir->id); +} + + +/// __attribute__((used)) ///Miranda NG adaptation, MSVC +static struct mwDirectory *dir_new(struct mwAddressBook *book, guint32 id) { +  struct mwDirectory *dir = g_new0(struct mwDirectory, 1); +  dir->service = book->service; +  dir->book = book; +  dir->id = id; +  map_guint_insert(book->dirs, id, dir); +  return dir; +} + + +/** called when book is removed from the service book map. Removed all +    directories as well */ +static void book_free(struct mwAddressBook *book) { +  g_hash_table_destroy(book->dirs); +  g_free(book->name); +} + + +/// __attribute__((used)) ///Miranda NG adaptation, MSVC +static void book_remove(struct mwAddressBook *book) { +  struct mwServiceDirectory *srvc = book->service; +  g_hash_table_remove(srvc->books, book->name); +} + + +static struct mwAddressBook *book_new(struct mwServiceDirectory *srvc, +				      const char *name, guint32 id) { +  struct mwAddressBook *book = g_new0(struct mwAddressBook, 1); +  book->service = srvc; +  book->id = id; +  book->name = g_strdup(name); +  book->dirs = map_guint_new_full((GDestroyNotify) dir_free); +  g_hash_table_insert(srvc->books, book->name, book); +  return book; +} + + +static const char *getName(struct mwService *srvc) { +  return "Address Book and Directory"; +} + + +static const char *getDesc(struct mwService *srvc) { +  return "Address book directory service for user and group lookups"; +} + + +static struct mwChannel *make_channel(struct mwServiceDirectory *srvc) { +  struct mwSession *session; +  struct mwChannelSet *cs; +  struct mwChannel *chan; + +  session = mwService_getSession(MW_SERVICE(srvc)); +  cs = mwSession_getChannels(session); +  chan = mwChannel_newOutgoing(cs); + +  mwChannel_setService(chan, MW_SERVICE(srvc)); +  mwChannel_setProtoType(chan, PROTOCOL_TYPE); +  mwChannel_setProtoVer(chan, PROTOCOL_VER); + +  return mwChannel_create(chan)? NULL: chan; +} + + +static void start(struct mwServiceDirectory *srvc) { +  struct mwChannel *chan; + +  chan = make_channel(srvc); +  if(chan) { +    srvc->channel = chan; +  } else { +    mwService_stopped(MW_SERVICE(srvc)); +    return; +  } +} + + +static void stop(struct mwServiceDirectory *srvc) { +  /* XXX */ + +  if(srvc->channel) { +    mwChannel_destroy(srvc->channel, ERR_SUCCESS, NULL); +    srvc->channel = NULL; +  } +} + + +static void clear(struct mwServiceDirectory *srvc) { +  struct mwDirectoryHandler *handler; + +  if(srvc->books) { +    g_hash_table_destroy(srvc->books); +    srvc->books = NULL; +  } +   +  /* clear the handler */ +  handler = srvc->handler; +  if(handler && handler->clear) +    handler->clear(srvc); +  srvc->handler = NULL; +} + + +static void recv_create(struct mwServiceDirectory *srvc, +			struct mwChannel *chan, +			struct mwMsgChannelCreate *msg) { + +  /* no way man, we call the shots around here */ +  mwChannel_destroy(chan, ERR_FAILURE, NULL); +} + + +static void recv_accept(struct mwServiceDirectory *srvc, +			struct mwChannel *chan, +			struct mwMsgChannelAccept *msg) { + +  g_return_if_fail(srvc->channel != NULL); +  g_return_if_fail(srvc->channel == chan); + +  if(MW_SERVICE_IS_STARTING(srvc)) { +    mwService_started(MW_SERVICE(srvc)); +       +  } else { +    mwChannel_destroy(chan, ERR_FAILURE, NULL); +  } +} + + +static void recv_destroy(struct mwServiceDirectory *srvc, +			 struct mwChannel *chan, +			 struct mwMsgChannelDestroy *msg) { + +  srvc->channel = NULL; +  mwService_stop(MW_SERVICE(srvc)); +  /** @todo session sense service */ +} + + +static void recv_list(struct mwServiceDirectory *srvc, +		      struct mwOpaque *data) { + +  struct mwGetBuffer *b; +  guint32 request, code, count; +  gboolean foo_1; +  guint16 foo_2; +   +  b = mwGetBuffer_wrap(data); +   +  guint32_get(b, &request); +  guint32_get(b, &code); +  guint32_get(b, &count); + +  gboolean_get(b, &foo_1); +  guint16_get(b, &foo_2); + +  if(foo_1 || foo_2) { +    mw_mailme_opaque(data, "received strange address book list"); +    mwGetBuffer_free(b); +    return; +  } + +  while(!mwGetBuffer_error(b) && count--) { +    guint32 id; +    char *name = NULL; + +    guint32_get(b, &id); +    mwString_get(b, &name); + +    book_new(srvc, name, id); +    g_free(name); +  } +} + + +static void recv_open(struct mwServiceDirectory *srvc, +		      struct mwOpaque *data) { + +  /* look up the directory associated with this request id,  +     mark it as open, and trigger the event */ +} + + +static void recv_search(struct mwServiceDirectory *srvc, +			struct mwOpaque *data) { + +  /* look up the directory associated with this request id, +     trigger the event */ +} + + +static void recv(struct mwServiceDirectory *srvc, +		 struct mwChannel *chan, +		 guint16 msg_type, struct mwOpaque *data) { +   +  g_return_if_fail(srvc != NULL); +  g_return_if_fail(chan != NULL); +  g_return_if_fail(chan == srvc->channel); +  g_return_if_fail(data != NULL); + +  switch(msg_type) { +  case action_list: +    recv_list(srvc, data); +    break; + +  case action_open: +    recv_open(srvc, data); +    break; + +  case action_close: +    ; /* I don't think we should receive these */ +    break; + +  case action_search: +    recv_search(srvc, data); +    break; + +  default: +    mw_mailme_opaque(data, "msg type 0x%04x in directory service", msg_type); +  } +} + + +struct mwServiceDirectory * +mwServiceDirectory_new(struct mwSession *session, +		       struct mwDirectoryHandler *handler) { + +  struct mwServiceDirectory *srvc; +  struct mwService *service; + +  g_return_val_if_fail(session != NULL, NULL); +  g_return_val_if_fail(handler != NULL, NULL); + +  srvc = g_new0(struct mwServiceDirectory, 1); +  service = MW_SERVICE(srvc); + +  mwService_init(service, session, SERVICE_DIRECTORY); +  service->get_name = getName; +  service->get_desc = getDesc; +  service->start = (mwService_funcStart) start; +  service->stop = (mwService_funcStop) stop; +  service->clear = (mwService_funcClear) clear; +  service->recv_create = (mwService_funcRecvCreate) recv_create; +  service->recv_accept = (mwService_funcRecvAccept) recv_accept; +  service->recv_destroy = (mwService_funcRecvDestroy) recv_destroy; +  service->recv = (mwService_funcRecv) recv; + +  srvc->handler = handler; +  srvc->requests = map_guint_new(); +  srvc->books = g_hash_table_new_full(g_str_hash, g_str_equal, +				      NULL, (GDestroyNotify) book_free); +  return srvc; +} + + +struct mwDirectoryHandler * +mwServiceDirectory_getHandler(struct mwServiceDirectory *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return srvc->handler; +} + + +int mwServiceDirectory_refreshAddressBooks(struct mwServiceDirectory *srvc) { +  struct mwChannel *chan; +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret; + +  g_return_val_if_fail(srvc != NULL, -1); + +  chan = srvc->channel; +  g_return_val_if_fail(chan != NULL, -1); + +  b = mwPutBuffer_new(); +  guint32_put(b, next_request_id(srvc)); + +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_send(chan, action_list, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +GList *mwServiceDirectory_getAddressBooks(struct mwServiceDirectory *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  g_return_val_if_fail(srvc->books != NULL, NULL); + +  return map_collect_values(srvc->books); +} + + +GList *mwServiceDirectory_getDirectories(struct mwServiceDirectory *srvc) { +  GList *bl, *ret = NULL; +   +  g_return_val_if_fail(srvc != NULL, NULL); +  g_return_val_if_fail(srvc->books != NULL, NULL); + +  bl = map_collect_values(srvc->books); +  for( ; bl; bl = g_list_delete_link(bl, bl)) { +    struct mwAddressBook *book = bl->data; +    ret = g_list_concat(ret, map_collect_values(book->dirs)); +  } + +  return ret; +} + + +GList *mwAddressBook_getDirectories(struct mwAddressBook *book) { +  g_return_val_if_fail(book != NULL, NULL); +  g_return_val_if_fail(book->dirs != NULL, NULL); + +  return map_collect_values(book->dirs); +} + + +const char *mwAddressBook_getName(struct mwAddressBook *book) { +  g_return_val_if_fail(book != NULL, NULL); +  return book->name; +} + + +struct mwDirectory *mwDirectory_new(struct mwAddressBook *book) { +  struct mwDirectory *dir; + +  g_return_val_if_fail(book != NULL, NULL); +  g_return_val_if_fail(book->service != NULL, NULL); + +  dir = g_new0(struct mwDirectory, 1); +  dir->service = book->service; +  dir->book = book; +  dir->state = mwDirectory_NEW; + +  return dir; +} + + +enum mwDirectoryState mwDirectory_getState(struct mwDirectory *dir) { +  g_return_val_if_fail(dir != NULL, mwDirectory_UNKNOWN); +  return dir->state; +} + + +void mwDirectory_setClientData(struct mwDirectory *dir, +			       gpointer data, GDestroyNotify clear) { + +  g_return_if_fail(dir != NULL); +  mw_datum_set(&dir->client_data, data, clear); +} + + +gpointer mwDirectory_getClientData(struct mwDirectory *dir) { +  g_return_val_if_fail(dir != NULL, NULL); +  return mw_datum_get(&dir->client_data); +} + + +void mwDirectory_removeClientData(struct mwDirectory *dir) { +  g_return_if_fail(dir != NULL); +  mw_datum_clear(&dir->client_data); +} + + +struct mwServiceDirectory *mwDirectory_getService(struct mwDirectory *dir) { +  g_return_val_if_fail(dir != NULL, NULL); +  g_return_val_if_fail(dir->book != NULL, NULL); +  return dir->book->service; +} + + +struct mwAddressBook *mwDirectory_getAddressBook(struct mwDirectory *dir) { +  g_return_val_if_fail(dir != NULL, NULL); +  return dir->book; +} + + +static int dir_open(struct mwDirectory *dir) { +  struct mwServiceDirectory *srvc; +  struct mwChannel *chan; +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret; + +  g_return_val_if_fail(dir != NULL, -1); + +  srvc = dir->service; +  g_return_val_if_fail(srvc != NULL, -1); + +  chan = srvc->channel; +  g_return_val_if_fail(chan != NULL, -1); + +  b = mwPutBuffer_new(); +  guint32_put(b, map_request(dir)); + +  /* unsure about these three bytes */ +  gboolean_put(b, FALSE); +  guint16_put(b, 0x0000); + +  guint32_put(b, dir->book->id); +  mwString_put(b, dir->book->name); + +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_send(chan, action_open, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +int mwDirectory_open(struct mwDirectory *dir, mwSearchHandler cb) { +  g_return_val_if_fail(dir != NULL, -1); +  g_return_val_if_fail(cb != NULL, -1); +  g_return_val_if_fail(MW_DIRECTORY_IS_NEW(dir), -1); + +  dir->state = mwDirectory_PENDING; +  dir->handler = cb; + +  return dir_open(dir); +} + + +int mwDirectory_next(struct mwDirectory *dir) {   +  struct mwServiceDirectory *srvc; +  struct mwChannel *chan; +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret; + +  g_return_val_if_fail(dir != NULL, -1); +  g_return_val_if_fail(MW_DIRECTORY_IS_OPEN(dir), -1); + +  srvc = dir->service; +  g_return_val_if_fail(srvc != NULL, -1); + +  chan = srvc->channel; +  g_return_val_if_fail(chan != NULL, -1); + +  b = mwPutBuffer_new(); +  guint32_put(b, map_request(dir)); +  guint32_put(b, dir->id); +  guint16_put(b, 0xffff);      /* some magic? */ +  guint32_put(b, 0x00000000);  /* next results */ + +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_send(chan, action_search, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +int mwDirectory_previous(struct mwDirectory *dir) { +  struct mwServiceDirectory *srvc; +  struct mwChannel *chan; +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret; + +  g_return_val_if_fail(dir != NULL, -1); +  g_return_val_if_fail(MW_DIRECTORY_IS_OPEN(dir), -1); + +  srvc = dir->service; +  g_return_val_if_fail(srvc != NULL, -1); + +  chan = srvc->channel; +  g_return_val_if_fail(chan != NULL, -1); + +  b = mwPutBuffer_new(); +  guint32_put(b, map_request(dir)); +  guint32_put(b, dir->id); +  guint16_put(b, 0x0061);      /* some magic? */ +  guint32_put(b, 0x00000001);  /* prev results */ + +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_send(chan, action_search, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +int mwDirectory_search(struct mwDirectory *dir, const char *query) { +  struct mwServiceDirectory *srvc; +  struct mwChannel *chan; +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret; + +  g_return_val_if_fail(dir != NULL, -1); +  g_return_val_if_fail(MW_DIRECTORY_IS_OPEN(dir), -1); +  g_return_val_if_fail(query != NULL, -1); +  g_return_val_if_fail(*query != '\0', -1); + +  srvc = dir->service; +  g_return_val_if_fail(srvc != NULL, -1); + +  chan = srvc->channel; +  g_return_val_if_fail(chan != NULL, -1); + +  b = mwPutBuffer_new(); +  guint32_put(b, map_request(dir)); +  guint32_put(b, dir->id); +  guint16_put(b, 0x0061);      /* some magic? */ +  guint32_put(b, 0x00000008);  /* seek results */ +  mwString_put(b, query); + +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_send(chan, action_search, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +static int dir_close(struct mwDirectory *dir) { +  struct mwServiceDirectory *srvc; +  struct mwChannel *chan; +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret; + +  g_return_val_if_fail(dir != NULL, -1); + +  srvc = dir->service; +  g_return_val_if_fail(srvc != NULL, -1); + +  chan = srvc->channel; +  g_return_val_if_fail(chan != NULL, -1); + +  b = mwPutBuffer_new(); +  guint32_put(b, next_request_id(dir->service)); +  guint32_put(b, dir->id); + +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_send(chan, action_close, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +int mwDirectory_destroy(struct mwDirectory *dir) { +  int ret = 0; + +  g_return_val_if_fail(dir != NULL, -1); + +  if(MW_DIRECTORY_IS_OPEN(dir) || MW_DIRECTORY_IS_PENDING(dir)) { +    ret = dir_close(dir); +  } +  dir_remove(dir); + +  return ret; +} + diff --git a/protocols/Sametime/src/meanwhile/src/srvc_ft.c b/protocols/Sametime/src/meanwhile/src/srvc_ft.c new file mode 100644 index 0000000000..38479e3452 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/srvc_ft.c @@ -0,0 +1,667 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + + +#include <glib/glist.h> + +#include "mw_channel.h" +#include "mw_common.h" +#include "mw_debug.h" +#include "mw_error.h" +#include "mw_message.h" +#include "mw_service.h" +#include "mw_session.h" +#include "mw_srvc_ft.h" +#include "mw_util.h" + + +#define PROTOCOL_TYPE  0x00000000 +#define PROTOCOL_VER   0x00000001 + + +/** send-on-channel type: FT transfer data */ +#define msg_TRANSFER  0x0001 + + +/** ack received transfer data */ +#define msg_RECEIVED  0x0002 + + +struct mwServiceFileTransfer { +  struct mwService service; + +  struct mwFileTransferHandler *handler; +  GList *transfers; +}; + + +struct mwFileTransfer { +  struct mwServiceFileTransfer *service; +   +  struct mwChannel *channel; +  struct mwIdBlock who; + +  enum mwFileTransferState state; + +  char *filename; +  char *message; + +  guint32 size; +  guint32 remaining; + +  struct mw_datum client_data; +}; + + +/** momentarily places a mwLoginInfo into a mwIdBlock */ +static void login_into_id(struct mwIdBlock *to, struct mwLoginInfo *from) { +  to->user = from->user_id; +  to->community = from->community; +} + + +static const char *ft_state_str(enum mwFileTransferState state) { +  switch(state) { +  case mwFileTransfer_NEW: +    return "new"; + +  case mwFileTransfer_PENDING: +    return "pending"; + +  case mwFileTransfer_OPEN: +    return "open"; + +  case mwFileTransfer_CANCEL_LOCAL: +    return "cancelled locally"; + +  case mwFileTransfer_CANCEL_REMOTE: +    return "cancelled remotely"; + +  case mwFileTransfer_DONE: +    return "done"; + +  case mwFileTransfer_ERROR: +    return "error"; + +  case mwFileTransfer_UNKNOWN: +  default: +    return "UNKNOWN"; +  } +} + + +static void ft_state(struct mwFileTransfer *ft, +		     enum mwFileTransferState state) { + +  g_return_if_fail(ft != NULL); + +  if(ft->state == state) return; + +  // Miranda NG adaptation +  //g_info("setting ft (%s, %s) state: %s", +  //	 NSTR(ft->who.user), NSTR(ft->who.community), +  //	 ft_state_str(state)); +  g_message("setting ft (%s, %s) state: %s", NSTR(ft->who.user), NSTR(ft->who.community), ft_state_str(state)); + +  ft->state = state; +} + + +static void recv_channelCreate(struct mwServiceFileTransfer *srvc, +			       struct mwChannel *chan, +			       struct mwMsgChannelCreate *msg) { + +  struct mwFileTransferHandler *handler; +  struct mwGetBuffer *b; + +  char *fnm, *txt; +  guint32 size, junk; +  gboolean b_err; + +  g_return_if_fail(srvc->handler != NULL); +  handler = srvc->handler; +   +  b = mwGetBuffer_wrap(&msg->addtl); + +  guint32_get(b, &junk); /* unknown */ +  mwString_get(b, &fnm); /* offered filename */ +  mwString_get(b, &txt); /* offering message */ +  guint32_get(b, &size); /* size of offered file */ +  /// Miranda NG adaptation - start - http://www.lilotux.net/~mikael/pub/meanwhile/ft_fix.diff +  /* guint32_get(b, &junk); */ /* unknown */ +  /// Miranda NG adaptation - end +  /* and we just skip an unknown guint16 at the end */ + +  b_err = mwGetBuffer_error(b); +  mwGetBuffer_free(b); + +  if(b_err) { +    g_warning("bad/malformed addtl in File Transfer service"); +    mwChannel_destroy(chan, ERR_FAILURE, NULL); + +  } else { +    struct mwIdBlock idb; +    struct mwFileTransfer *ft; + +    login_into_id(&idb, mwChannel_getUser(chan)); +    ft = mwFileTransfer_new(srvc, &idb, txt, fnm, size); +    ft->channel = chan; +    ft_state(ft, mwFileTransfer_PENDING); + +    mwChannel_setServiceData(chan, ft, NULL); + +    if(handler->ft_offered) +      handler->ft_offered(ft); +  } + +  g_free(fnm); +  g_free(txt); +} + + +static void recv_channelAccept(struct mwServiceFileTransfer *srvc, +			       struct mwChannel *chan, +			       struct mwMsgChannelAccept *msg) { + +  struct mwFileTransferHandler *handler; +  struct mwFileTransfer *ft; + +  g_return_if_fail(srvc->handler != NULL); +  handler = srvc->handler; + +  ft = mwChannel_getServiceData(chan); +  g_return_if_fail(ft != NULL); + +  ft_state(ft, mwFileTransfer_OPEN); + +  if(handler->ft_opened) +    handler->ft_opened(ft); +} + + +static void recv_channelDestroy(struct mwServiceFileTransfer *srvc, +				struct mwChannel *chan, +				struct mwMsgChannelDestroy *msg) { + +  struct mwFileTransferHandler *handler; +  struct mwFileTransfer *ft; +  guint32 code; + +  code = msg->reason; + +  g_return_if_fail(srvc->handler != NULL); +  handler = srvc->handler; + +  ft = mwChannel_getServiceData(chan); +  g_return_if_fail(ft != NULL); + +  ft->channel = NULL; + +  if(! mwFileTransfer_isDone(ft)) +    ft_state(ft, mwFileTransfer_CANCEL_REMOTE); + +  mwFileTransfer_close(ft, code); +} + + +static void recv_TRANSFER(struct mwFileTransfer *ft, +			  struct mwOpaque *data) { + +  struct mwServiceFileTransfer *srvc; +  struct mwFileTransferHandler *handler; +   +  srvc = ft->service; +  handler = srvc->handler; + +  g_return_if_fail(mwFileTransfer_isOpen(ft)); + +  if(data->len > ft->remaining) { +    /* @todo handle error */ + +  } else { +    ft->remaining -= data->len; + +    if(! ft->remaining) +      ft_state(ft, mwFileTransfer_DONE); +     +    if(handler->ft_recv) +      handler->ft_recv(ft, data); +  } +} + + +static void recv_RECEIVED(struct mwFileTransfer *ft, +			  struct mwOpaque *data) { + +  struct mwServiceFileTransfer *srvc; +  struct mwFileTransferHandler *handler; +   +  srvc = ft->service; +  handler = srvc->handler; + +  if(! ft->remaining) +    ft_state(ft, mwFileTransfer_DONE); + +  if(handler->ft_ack) +    handler->ft_ack(ft); + +  if(! ft->remaining) +    mwFileTransfer_close(ft, mwFileTransfer_SUCCESS); +} + + +static void recv(struct mwService *srvc, struct mwChannel *chan, +		 guint16 type, struct mwOpaque *data) { + +  struct mwFileTransfer *ft; +   +  ft = mwChannel_getServiceData(chan); +  g_return_if_fail(ft != NULL); + +  switch(type) { +  case msg_TRANSFER: +    recv_TRANSFER(ft, data); +    break; + +  case msg_RECEIVED: +    recv_RECEIVED(ft, data); +    break; + +  default: +    mw_mailme_opaque(data, "unknown message in ft service: 0x%04x", type); +  } +} + + +static void clear(struct mwServiceFileTransfer *srvc) { +  struct mwFileTransferHandler *h; +   +  h = srvc->handler; +  if(h && h->clear) +    h->clear(srvc); +  srvc->handler = NULL; +} + + +static const char *name(struct mwService *srvc) { +  return "File Transfer"; +} + + +static const char *desc(struct mwService *srvc) { +  return "Provides file transfer capabilities through the community server"; +} + + +static void start(struct mwService *srvc) { +  mwService_started(srvc); +} + + +static void stop(struct mwServiceFileTransfer *srvc) { +  while(srvc->transfers) { +    mwFileTransfer_free(srvc->transfers->data); +  } + +  mwService_stopped(MW_SERVICE(srvc)); +} + + +struct mwServiceFileTransfer * +mwServiceFileTransfer_new(struct mwSession *session, +			  struct mwFileTransferHandler *handler) { + +  struct mwServiceFileTransfer *srvc_ft; +  struct mwService *srvc; + +  g_return_val_if_fail(session != NULL, NULL); +  g_return_val_if_fail(handler != NULL, NULL); + +  srvc_ft = g_new0(struct mwServiceFileTransfer, 1); +  srvc = MW_SERVICE(srvc_ft); + +  mwService_init(srvc, session, mwService_FILE_TRANSFER); +  srvc->recv_create = (mwService_funcRecvCreate) recv_channelCreate; +  srvc->recv_accept = (mwService_funcRecvAccept) recv_channelAccept; +  srvc->recv_destroy = (mwService_funcRecvDestroy) recv_channelDestroy; +  srvc->recv = recv; +  srvc->clear = (mwService_funcClear) clear; +  srvc->get_name = name; +  srvc->get_desc = desc; +  srvc->start = start; +  srvc->stop = (mwService_funcStop) stop; + +  srvc_ft->handler = handler; + +  return srvc_ft; +} + + +struct mwFileTransferHandler * +mwServiceFileTransfer_getHandler(struct mwServiceFileTransfer *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return srvc->handler; +} + + +const GList * +mwServiceFileTransfer_getTransfers(struct mwServiceFileTransfer *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return srvc->transfers; +} + + +/// Miranda NG adaptation start - new method +struct mwService * +mwServiceFileTransfer_getService(struct mwServiceFileTransfer *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return &(srvc->service); +} +/// Miranda NG adaptation end + + +struct mwFileTransfer * +mwFileTransfer_new(struct mwServiceFileTransfer *srvc, +		   const struct mwIdBlock *who, const char *msg, +		   const char *filename, guint32 filesize) { +   +  struct mwFileTransfer *ft; + +  g_return_val_if_fail(srvc != NULL, NULL); +  g_return_val_if_fail(who != NULL, NULL); +   +  ft = g_new0(struct mwFileTransfer, 1); +  ft->service = srvc; +  mwIdBlock_clone(&ft->who, who); +  ft->filename = g_strdup(filename); +  ft->message = g_strdup(msg); +  ft->size = ft->remaining = filesize; + +  ft_state(ft, mwFileTransfer_NEW); + +  /* stick a reference in the service */ +  srvc->transfers = g_list_prepend(srvc->transfers, ft); + +  return ft; +} + + +struct mwServiceFileTransfer * +mwFileTransfer_getService(struct mwFileTransfer *ft) { +  g_return_val_if_fail(ft != NULL, NULL); +  return ft->service; +} + + +enum mwFileTransferState +mwFileTransfer_getState(struct mwFileTransfer *ft) { +  g_return_val_if_fail(ft != NULL, mwFileTransfer_UNKNOWN); +  return ft->state; +} + + +const struct mwIdBlock * +mwFileTransfer_getUser(struct mwFileTransfer *ft) { +  g_return_val_if_fail(ft != NULL, NULL); +  return &ft->who; +} + + +const char * +mwFileTransfer_getMessage(struct mwFileTransfer *ft) { +  g_return_val_if_fail(ft != NULL, NULL); +  return ft->message; +} + + +const char * +mwFileTransfer_getFileName(struct mwFileTransfer *ft) { +  g_return_val_if_fail(ft != NULL, NULL); +  return ft->filename; +} + + +guint32 mwFileTransfer_getFileSize(struct mwFileTransfer *ft) { +  g_return_val_if_fail(ft != NULL, 0); +  return ft->size; +} + + +guint32 mwFileTransfer_getRemaining(struct mwFileTransfer *ft) { +  g_return_val_if_fail(ft != NULL, 0); +  return ft->remaining; +} + + +int mwFileTransfer_accept(struct mwFileTransfer *ft) { +  struct mwServiceFileTransfer *srvc; +  struct mwFileTransferHandler *handler; +  int ret; + +  g_return_val_if_fail(ft != NULL, -1); +  g_return_val_if_fail(ft->channel != NULL, -1); +  g_return_val_if_fail(mwFileTransfer_isPending(ft), -1); +  g_return_val_if_fail(mwChannel_isIncoming(ft->channel), -1); +  g_return_val_if_fail(mwChannel_isState(ft->channel, mwChannel_WAIT), -1); + +  g_return_val_if_fail(ft->service != NULL, -1); +  srvc = ft->service; + +  g_return_val_if_fail(srvc->handler != NULL, -1); +  handler = srvc->handler; + +  ret = mwChannel_accept(ft->channel); + +  if(ret) { +    mwFileTransfer_close(ft, ERR_FAILURE); + +  } else { +    ft_state(ft, mwFileTransfer_OPEN); +    if(handler->ft_opened) +      handler->ft_opened(ft); +  } + +  return ret; +} + + +static void ft_create_chan(struct mwFileTransfer *ft) { +  struct mwSession *s; +  struct mwChannelSet *cs; +  struct mwChannel *chan; +  struct mwLoginInfo *login; +  struct mwPutBuffer *b; +   +  /* we only should be calling this if there isn't a channel already +     associated with the conversation */ +  g_return_if_fail(ft != NULL); +  g_return_if_fail(mwFileTransfer_isNew(ft)); +  g_return_if_fail(ft->channel == NULL); +		    +  s = mwService_getSession(MW_SERVICE(ft->service)); +  cs = mwSession_getChannels(s); + +  chan = mwChannel_newOutgoing(cs); +  mwChannel_setService(chan, MW_SERVICE(ft->service)); +  mwChannel_setProtoType(chan, PROTOCOL_TYPE); +  mwChannel_setProtoVer(chan, PROTOCOL_VER); + +  /* offer all known ciphers */ +  mwChannel_populateSupportedCipherInstances(chan); + +  /* set the target */ +  login = mwChannel_getUser(chan); +  login->user_id = g_strdup(ft->who.user); +  login->community = g_strdup(ft->who.community); + +  /* compose the addtl create */ +  b = mwPutBuffer_new(); +  guint32_put(b, 0x00); +  mwString_put(b, ft->filename); +  mwString_put(b, ft->message); +  guint32_put(b, ft->size); +  guint32_put(b, 0x00); +  guint16_put(b, 0x00); + +  mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b); + +  ft->channel = mwChannel_create(chan)? NULL: chan; +  if(ft->channel) { +    mwChannel_setServiceData(ft->channel, ft, NULL); +  } +} + + +int mwFileTransfer_offer(struct mwFileTransfer *ft) { +  struct mwServiceFileTransfer *srvc; +  struct mwFileTransferHandler *handler; + +  g_return_val_if_fail(ft != NULL, -1); +  g_return_val_if_fail(ft->channel == NULL, -1); +  g_return_val_if_fail(mwFileTransfer_isNew(ft), -1); + +  g_return_val_if_fail(ft->service != NULL, -1); +  srvc = ft->service; + +  g_return_val_if_fail(srvc->handler != NULL, -1); +  handler = srvc->handler; + +  ft_create_chan(ft); +  if(ft->channel) { +    ft_state(ft, mwFileTransfer_PENDING); +  } else { +    ft_state(ft, mwFileTransfer_ERROR); +    mwFileTransfer_close(ft, ERR_FAILURE); +  } + +  return 0; +} + + +int mwFileTransfer_close(struct mwFileTransfer *ft, guint32 code) { +  struct mwServiceFileTransfer *srvc; +  struct mwFileTransferHandler *handler; +  int ret = 0; + +  g_return_val_if_fail(ft != NULL, -1); + +  if(mwFileTransfer_isOpen(ft)) +    ft_state(ft, mwFileTransfer_CANCEL_LOCAL); + +  if(ft->channel) { +    ret = mwChannel_destroy(ft->channel, code, NULL); +    ft->channel = NULL; +  } + +  srvc = ft->service; +  g_return_val_if_fail(srvc != NULL, ret); + +  handler = srvc->handler; +  g_return_val_if_fail(handler != NULL, ret); + +  if(handler->ft_closed) +    handler->ft_closed(ft, code); + +  return ret; +} + + +void mwFileTransfer_free(struct mwFileTransfer *ft) { +  struct mwServiceFileTransfer *srvc; + +  if(! ft) return; + +  srvc = ft->service; +  if(srvc) +    srvc->transfers = g_list_remove(srvc->transfers, ft); + +  if(ft->channel) { +    mwChannel_destroy(ft->channel, mwFileTransfer_SUCCESS, NULL); +    ft->channel = NULL; +  } + +  mwFileTransfer_removeClientData(ft); + +  mwIdBlock_clear(&ft->who); +  g_free(ft->filename); +  g_free(ft->message); +  g_free(ft); +} + + +int mwFileTransfer_send(struct mwFileTransfer *ft, +			struct mwOpaque *data) { + +  struct mwChannel *chan; +  int ret; + +  g_return_val_if_fail(ft != NULL, -1); +  g_return_val_if_fail(mwFileTransfer_isOpen(ft), -1); +  g_return_val_if_fail(ft->channel != NULL, -1); +  chan = ft->channel; + +  g_return_val_if_fail(mwChannel_isOutgoing(chan), -1); + +  if(data->len > ft->remaining) { +    /* @todo handle error */ +    return -1; +  } + +  ret = mwChannel_send(chan, msg_TRANSFER, data); +  if(! ret) ft->remaining -= data->len; +   +  /* we're not done until we receive an ACK for the last piece of +     outgoing data */ + +  return ret; +} + + +int mwFileTransfer_ack(struct mwFileTransfer *ft) { +  struct mwChannel *chan; + +  g_return_val_if_fail(ft != NULL, -1); + +  chan = ft->channel; +  g_return_val_if_fail(chan != NULL, -1); +  g_return_val_if_fail(mwChannel_isIncoming(chan), -1); + +  return mwChannel_sendEncrypted(chan, msg_RECEIVED, NULL, FALSE); +} + + +void mwFileTransfer_setClientData(struct mwFileTransfer *ft, +				  gpointer data, GDestroyNotify clean) { +  g_return_if_fail(ft != NULL); +  mw_datum_set(&ft->client_data, data, clean); +} + + +gpointer mwFileTransfer_getClientData(struct mwFileTransfer *ft) { +  g_return_val_if_fail(ft != NULL, NULL); +  return mw_datum_get(&ft->client_data); +} + + +void mwFileTransfer_removeClientData(struct mwFileTransfer *ft) { +  g_return_if_fail(ft != NULL); +  mw_datum_clear(&ft->client_data); +} + diff --git a/protocols/Sametime/src/meanwhile/src/srvc_im.c b/protocols/Sametime/src/meanwhile/src/srvc_im.c new file mode 100644 index 0000000000..b03991d3b9 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/srvc_im.c @@ -0,0 +1,1095 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <glib.h> +#include <glib/glist.h> +#include <string.h> + +#include "mw_channel.h" +#include "mw_debug.h" +#include "mw_error.h" +#include "mw_message.h" +#include "mw_service.h" +#include "mw_session.h" +#include "mw_srvc_im.h" +#include "mw_util.h" + + +#define PROTOCOL_TYPE  0x00001000 +#define PROTOCOL_VER   0x00000003 + + +/* data for the addtl blocks of channel creation */ +#define mwImAddtlA_NORMAL  0x00000001 + +#define mwImAddtlB_NORMAL      0x00000001  /**< standard */ +#define mwImAddtlB_PRECONF     0x00000019  /**< pre-conference chat */ +#define mwImAddtlB_NOTESBUDDY  0x00033453  /**< notesbuddy */ + +#define mwImAddtlC_NORMAL  0x00000002 + + +/* send-on-channel message type */ +#define msg_MESSAGE  0x0064  /**< IM message */ + + +#define BREAKUP  2048 + + +/* which type of im? */ +enum mwImType { +  mwIm_TEXT  = 0x00000001,  /**< text message */ +  mwIm_DATA  = 0x00000002,  /**< status message (usually) */ +}; + + +/* which type of data im? */ +enum mwImDataType { +  mwImData_TYPING   = 0x00000001,  /**< common use typing indicator */ +  mwImData_SUBJECT  = 0x00000003,  /**< notesbuddy IM topic */ +  mwImData_HTML     = 0x00000004,  /**< notesbuddy HTML message */ +  mwImData_MIME     = 0x00000005,  /**< notesbuddy MIME message, w/image */ +  mwImData_TIMESTAMP = 0x00000006, /**< notesbuddy timestamp */ + +  mwImData_INVITE   = 0x0000000a,  /**< Places invitation */ + +  mwImData_MULTI_START  = 0x00001388, +  mwImData_MULTI_STOP   = 0x00001389, +}; + + +/** @todo might be appropriate to make a couple of hashtables to +    reference conversations by channel and target */ +struct mwServiceIm { +  struct mwService service; + +  enum mwImClientType features; + +  struct mwImHandler *handler; +  GList *convs;  /**< list of struct im_convo */ +}; + + +struct mwConversation { +  struct mwServiceIm *service;  /**< owning service */ +  struct mwChannel *channel;    /**< channel */ +  struct mwIdBlock target;      /**< conversation target */ + +  gboolean ext_id;              /**< special treatment, external ID */ + +  /** state of the conversation, based loosely on the state of its +      underlying channel */ +  enum mwConversationState state; + +  enum mwImClientType features; + +  GString *multi;               /**< buffer for multi-chunk message */ +  enum mwImSendType multi_type; /**< type of incoming multi-chunk message */ + +  struct mw_datum client_data; +}; + + +/** momentarily places a mwLoginInfo into a mwIdBlock */ +static void login_into_id(struct mwIdBlock *to, struct mwLoginInfo *from) { +  to->user = from->user_id; +  to->community = from->community; +} + + +static struct mwConversation *convo_find_by_user(struct mwServiceIm *srvc, +						 struct mwIdBlock *to) { +  GList *l; + +  for(l = srvc->convs; l; l = l->next) { +    struct mwConversation *c = l->data; +    if(mwIdBlock_equal(&c->target, to)) +       return c; +  } + +  return NULL; +} + + +static const char *conv_state_str(enum mwConversationState state) { +  switch(state) { +  case mwConversation_CLOSED: +    return "closed"; + +  case mwConversation_OPEN: +    return "open"; + +  case mwConversation_PENDING: +    return "pending"; + +  case mwConversation_UNKNOWN: +  default: +    return "UNKNOWN"; +  } +} + + +static void convo_set_state(struct mwConversation *conv, +			    enum mwConversationState state) { + +  g_return_if_fail(conv != NULL); + +  if(conv->state != state) { +    // Miranda NG adaptation +    //g_info("setting conversation (%s, %s) state: %s", +	//   NSTR(conv->target.user), NSTR(conv->target.community), +	//   conv_state_str(state)); +    g_message("setting conversation (%s, %s) state: %s", NSTR(conv->target.user), NSTR(conv->target.community), conv_state_str(state)); +    conv->state = state; +  } +} + + +struct mwConversation *mwServiceIm_findConversation(struct mwServiceIm *srvc, +						    struct mwIdBlock *to) { +  g_return_val_if_fail(srvc != NULL, NULL); +  g_return_val_if_fail(to != NULL, NULL); + +  return convo_find_by_user(srvc, to); +} + + +struct mwConversation *mwServiceIm_getConversation(struct mwServiceIm *srvc, +						   struct mwIdBlock *to) { +  struct mwConversation *c; + +  g_return_val_if_fail(srvc != NULL, NULL); +  g_return_val_if_fail(to != NULL, NULL); + +  c = convo_find_by_user(srvc, to); +  if(! c) { +    c = g_new0(struct mwConversation, 1); +    c->service = srvc; +    mwIdBlock_clone(&c->target, to); +    c->state = mwConversation_CLOSED; +    c->features = srvc->features; + +    /* mark external users */ +    /* c->ext_id = g_str_has_prefix(to->user, "@E "); */ + +    srvc->convs = g_list_prepend(srvc->convs, c); +  } + +  return c; +} + + +static void convo_create_chan(struct mwConversation *c) { +  struct mwSession *s; +  struct mwChannelSet *cs; +  struct mwChannel *chan; +  struct mwLoginInfo *login; +  struct mwPutBuffer *b; + +  /* we only should be calling this if there isn't a channel already +     associated with the conversation */ +  g_return_if_fail(c != NULL); +  g_return_if_fail(mwConversation_isPending(c)); +  g_return_if_fail(c->channel == NULL); + +  s = mwService_getSession(MW_SERVICE(c->service)); +  cs = mwSession_getChannels(s); + +  chan = mwChannel_newOutgoing(cs); +  mwChannel_setService(chan, MW_SERVICE(c->service)); +  mwChannel_setProtoType(chan, PROTOCOL_TYPE); +  mwChannel_setProtoVer(chan, PROTOCOL_VER); + +  /* offer all known ciphers */ +  mwChannel_populateSupportedCipherInstances(chan); + +  /* set the target */ +  login = mwChannel_getUser(chan); +  login->user_id = g_strdup(c->target.user); +  login->community = g_strdup(c->target.community); + +  /* compose the addtl create, with optional FANCY HTML! */ +  b = mwPutBuffer_new(); +  guint32_put(b, mwImAddtlA_NORMAL); +  guint32_put(b, c->features); +  mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b); + +  c->channel = mwChannel_create(chan)? NULL: chan; +  if(c->channel) { +    mwChannel_setServiceData(c->channel, c, NULL); +  } +} + + +void mwConversation_open(struct mwConversation *conv) { +  g_return_if_fail(conv != NULL); +  g_return_if_fail(mwConversation_isClosed(conv)); + +  convo_set_state(conv, mwConversation_PENDING); +  convo_create_chan(conv); +} + + +static void convo_opened(struct mwConversation *conv) { +  struct mwImHandler *h = NULL; + +  g_return_if_fail(conv != NULL); +  g_return_if_fail(conv->service != NULL); + +  convo_set_state(conv, mwConversation_OPEN); +  h = conv->service->handler; + +  g_return_if_fail(h != NULL); + +  if(h->conversation_opened) +    h->conversation_opened(conv); +} + + +static void convo_free(struct mwConversation *conv) { +  struct mwServiceIm *srvc; + +  mwConversation_removeClientData(conv); + +  srvc = conv->service; +  srvc->convs = g_list_remove_all(srvc->convs, conv); + +  mwIdBlock_clear(&conv->target); +  g_free(conv); +} + + +static int send_accept(struct mwConversation *c) { + +  struct mwChannel *chan = c->channel; +  struct mwSession *s = mwChannel_getSession(chan); +  struct mwUserStatus *stat = mwSession_getUserStatus(s); + +  struct mwPutBuffer *b; +  struct mwOpaque *o; + +  b = mwPutBuffer_new(); +  guint32_put(b, mwImAddtlA_NORMAL); +  guint32_put(b, c->features); +  guint32_put(b, mwImAddtlC_NORMAL); +  mwUserStatus_put(b, stat); + +  o = mwChannel_getAddtlAccept(chan); +  mwOpaque_clear(o); +  mwPutBuffer_finalize(o, b); + +  return mwChannel_accept(chan); +} + + +static void recv_channelCreate(struct mwService *srvc, +			       struct mwChannel *chan, +			       struct mwMsgChannelCreate *msg) { + +  /* - ensure it's the right service,proto,and proto ver +     - check the opaque for the right opaque junk +     - if not, close channel +     - compose & send a channel accept +  */ + +  struct mwServiceIm *srvc_im = (struct mwServiceIm *) srvc; +  struct mwImHandler *handler; +  struct mwSession *s; +  struct mwUserStatus *stat; +  guint32 x, y, z; +  struct mwGetBuffer *b; +  struct mwConversation *c = NULL; +  struct mwIdBlock idb; + +  handler = srvc_im->handler; +  s = mwChannel_getSession(chan); +  stat = mwSession_getUserStatus(s); + +  /* ensure the appropriate service/proto/ver */ +  x = mwChannel_getServiceId(chan); +  y = mwChannel_getProtoType(chan); +  z = mwChannel_getProtoVer(chan); + +  if( (x != mwService_IM) || (y != PROTOCOL_TYPE) || (z != PROTOCOL_VER) ) { +    g_warning("unacceptable service, proto, ver:" +	      " 0x%08x, 0x%08x, 0x%08x", x, y, z); +    mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL); +    return; +  } + +  /* act upon the values in the addtl block */ +  b = mwGetBuffer_wrap(&msg->addtl); +  guint32_get(b, &x); +  guint32_get(b, &y); +  z = (guint) mwGetBuffer_error(b); +  mwGetBuffer_free(b); + +  if(z /* buffer error, BOOM! */ ) { +    g_warning("bad/malformed addtl in IM service"); +    mwChannel_destroy(chan, ERR_FAILURE, NULL); +    return; + +  } else if(x != mwImAddtlA_NORMAL) { +    g_message("unknown params: 0x%08x, 0x%08x", x, y); +    mwChannel_destroy(chan, ERR_IM_NOT_REGISTERED, NULL); +    return; +     +  } else if(y == mwImAddtlB_PRECONF) { +    if(! handler->place_invite) { +      // Miranda NG adaptation +      //g_info("rejecting place-invite channel"); +      g_message("rejecting place-invite channel"); +      mwChannel_destroy(chan, ERR_IM_NOT_REGISTERED, NULL); +      return; + +    } else { +      // Miranda NG adaptation +      //g_info("accepting place-invite channel"); +      g_message("accepting place-invite channel"); +    } + +  } else if(y != mwImClient_PLAIN && y != srvc_im->features) { +    /** reject what we do not understand */ +    mwChannel_destroy(chan, ERR_IM_NOT_REGISTERED, NULL); +    return; + +  } else if(stat->status == mwStatus_BUSY) { +    // Miranda NG adaptation +    //g_info("rejecting IM channel due to DND status"); +    g_message("rejecting IM channel due to DND status"); +    mwChannel_destroy(chan, ERR_CLIENT_USER_DND, NULL); +    return; +  } + +  login_into_id(&idb, mwChannel_getUser(chan)); + +#if 0 +  c = convo_find_by_user(srvc_im, &idb); +#endif + +  if(! c) { +    c = g_new0(struct mwConversation, 1); +    c->service = srvc_im; +    srvc_im->convs = g_list_prepend(srvc_im->convs, c); +  } + +#if 0 +  /* we're going to re-associate any existing conversations with this +     new channel. That means closing any existing ones */ +  if(c->channel) { +    // Miranda NG adaptation +    //g_info("closing existing IM channel 0x%08x", mwChannel_getId(c->channel)); +    g_message("closing existing IM channel 0x%08x", mwChannel_getId(c->channel)); +    mwConversation_close(c, ERR_SUCCESS); +  } +#endif + +  /* set up the conversation with this channel, target, and be fancy +     if the other side requested it */ +  c->channel = chan; +  mwIdBlock_clone(&c->target, &idb); +  c->features = y; +  convo_set_state(c, mwConversation_PENDING); +  mwChannel_setServiceData(c->channel, c, NULL); + +  if(send_accept(c)) { +    g_warning("sending IM channel accept failed"); +    mwConversation_free(c); + +  } else { +    convo_opened(c); +  } +} + + +static void recv_channelAccept(struct mwService *srvc, struct mwChannel *chan, +			       struct mwMsgChannelAccept *msg) { + +  struct mwConversation *conv; + +  conv = mwChannel_getServiceData(chan); +  if(! conv) { +    g_warning("received channel accept for non-existant conversation"); +    mwChannel_destroy(chan, ERR_FAILURE, NULL); +    return; +  } + +  convo_opened(conv); +} + + +static void recv_channelDestroy(struct mwService *srvc, struct mwChannel *chan, +				struct mwMsgChannelDestroy *msg) { + +  struct mwConversation *c; + +  c = mwChannel_getServiceData(chan); +  g_return_if_fail(c != NULL); + +  c->channel = NULL; + +  if(mwChannel_isState(chan, mwChannel_ERROR)) { + +    /* checking for failure on the receiving end to accept html +       messages. Fail-over to a non-html format on a new channel for +       the convo */ +    if(c->features != mwImClient_PLAIN +       && (msg->reason == ERR_IM_NOT_REGISTERED || +	   msg->reason == ERR_SERVICE_NO_SUPPORT)) { + +      g_debug("falling back on a plaintext conversation"); +      c->features = mwImClient_PLAIN; +      convo_create_chan(c); +      return; +    } +  } + +  mwConversation_close(c, msg->reason); +} + + +static void convo_recv(struct mwConversation *conv, enum mwImSendType type, +		       gconstpointer msg) { + +  struct mwServiceIm *srvc; +  struct mwImHandler *handler; + +  g_return_if_fail(conv != NULL); + +  srvc = conv->service; +  g_return_if_fail(srvc != NULL); + +  handler = srvc->handler; +  if(handler && handler->conversation_recv) +    handler->conversation_recv(conv, type, msg); +} + + +static void convo_multi_start(struct mwConversation *conv) { +  g_return_if_fail(conv->multi == NULL); +  conv->multi = g_string_new(NULL); +} + + +static void convo_multi_stop(struct mwConversation *conv) { + +  g_return_if_fail(conv->multi != NULL); + +  /* actually send it */ +  convo_recv(conv, conv->multi_type, conv->multi->str); + +  /* clear up the multi buffer */ +  g_string_free(conv->multi, TRUE); +  conv->multi = NULL; +} + + +static void recv_text(struct mwServiceIm *srvc, struct mwChannel *chan, +		      struct mwGetBuffer *b) { + +  struct mwConversation *c; +  char *text = NULL; + +  mwString_get(b, &text); + +  if(! text) return; + +  c = mwChannel_getServiceData(chan); +  if(c) { +    if(c->multi) { +      g_string_append(c->multi, text); + +    } else { +      convo_recv(c, mwImSend_PLAIN, text);  +    } +  } + +  g_free(text); +} + + +static void convo_invite(struct mwConversation *conv, +			 struct mwOpaque *o) { + +  struct mwServiceIm *srvc; +  struct mwImHandler *handler; + +  struct mwGetBuffer *b; +  char *title, *name, *msg; +  char *unkn, *host; +  guint16 with_who; + +  // Miranda NG adaptation +  //g_info("convo_invite"); +  g_message("convo_invite"); + +  srvc = conv->service; +  handler = srvc->handler; + +  g_return_if_fail(handler != NULL); +  g_return_if_fail(handler->place_invite != NULL); + +  b = mwGetBuffer_wrap(o); +  mwGetBuffer_advance(b, 4); +  mwString_get(b, &title); +  mwString_get(b, &msg); +  mwGetBuffer_advance(b, 19); +  mwString_get(b, &name); + +  /* todo: add a mwString_skip */ +  mwString_get(b, &unkn); +  mwString_get(b, &host); +  g_free(unkn); +  g_free(host); + +  /* hack. Sometimes incoming convo invitation channels won't have the +     owner id block filled in */ +  guint16_get(b, &with_who); +  if(with_who && !conv->target.user) { +    char *login; +    mwString_get(b, &conv->target.user); +    mwString_get(b, &login); g_free(login); +    mwString_get(b, &conv->target.community); +  }   + +  if(mwGetBuffer_error(b)) { +    mw_mailme_opaque(o, "problem with place invite over IM service"); +  } else { +    handler->place_invite(conv, msg, title, name); +  } + +  mwGetBuffer_free(b); +  g_free(msg); +  g_free(title); +  g_free(name); +} + + +static void recv_data(struct mwServiceIm *srvc, struct mwChannel *chan, +		      struct mwGetBuffer *b) { + +  struct mwConversation *conv; +  guint32 type, subtype; +  struct mwOpaque o = { 0, 0 }; +  char *x; + +  guint32_get(b, &type); +  guint32_get(b, &subtype); +  mwOpaque_get(b, &o); + +  if(mwGetBuffer_error(b)) { +    mwOpaque_clear(&o); +    return; +  } + +  conv = mwChannel_getServiceData(chan); +  if(! conv) return; + +  switch(type) { +  case mwImData_TYPING: +    convo_recv(conv, mwImSend_TYPING, GINT_TO_POINTER(! subtype)); +    break; + +  case mwImData_HTML: +    if(o.len) { +      if(conv->multi) { +	g_string_append_len(conv->multi, (char *) o.data, o.len); +	conv->multi_type = mwImSend_HTML; + +      } else { +	x = g_strndup((char *) o.data, o.len); +	convo_recv(conv, mwImSend_HTML, x); +	g_free(x); +      } +    } +    break; + +  case mwImData_SUBJECT: +    x = g_strndup((char *) o.data, o.len); +    convo_recv(conv, mwImSend_SUBJECT, x); +    g_free(x); +    break; + +  case mwImData_MIME: +    if(conv->multi) { +      g_string_append_len(conv->multi, (char *) o.data, o.len); +      conv->multi_type = mwImSend_MIME; + +    } else { +      x = g_strndup((char *) o.data, o.len); +      convo_recv(conv, mwImSend_MIME, x); +      g_free(x); +    } +    break; + +  case mwImData_TIMESTAMP: +    /* todo */ +    break; + +  case mwImData_INVITE: +    convo_invite(conv, &o); +    break; + +  case mwImData_MULTI_START: +    convo_multi_start(conv); +    break; + +  case mwImData_MULTI_STOP: +    convo_multi_stop(conv); +    break; + +  default: +     +    mw_mailme_opaque(&o, "unknown data message type in IM service:" +		     " (0x%08x, 0x%08x)", type, subtype); +  } + +  mwOpaque_clear(&o); +} + + +static void recv(struct mwService *srvc, struct mwChannel *chan, +		 guint16 type, struct mwOpaque *data) { + +  /* - ensure message type is something we want +     - parse message type into either mwIMText or mwIMData +     - handle +  */ + +  struct mwGetBuffer *b; +  guint32 mt; + +  g_return_if_fail(type == msg_MESSAGE); + +  b = mwGetBuffer_wrap(data); +  guint32_get(b, &mt); + +  if(mwGetBuffer_error(b)) { +    g_warning("failed to parse message for IM service"); +    mwGetBuffer_free(b); +    return; +  } + +  switch(mt) { +  case mwIm_TEXT: +    recv_text((struct mwServiceIm *) srvc, chan, b); +    break; + +  case mwIm_DATA: +    recv_data((struct mwServiceIm *) srvc, chan, b); +    break; + +  default: +    g_warning("unknown message type 0x%08x for IM service", mt); +  } + +  if(mwGetBuffer_error(b)) +    g_warning("failed to parse message type 0x%08x for IM service", mt); + +  mwGetBuffer_free(b); +} + + +static void clear(struct mwServiceIm *srvc) { +  struct mwImHandler *h; + +  while(srvc->convs) +    convo_free(srvc->convs->data); + +  h = srvc->handler; +  if(h && h->clear) +    h->clear(srvc); +  srvc->handler = NULL; +} + + +static const char *name(struct mwService *srvc) { +  return "Instant Messaging"; +} + + +static const char *desc(struct mwService *srvc) { +  return "IM service with Standard and NotesBuddy features"; +} + + +static void start(struct mwService *srvc) { +  mwService_started(srvc); +} + + +static void stop(struct mwServiceIm *srvc) { + +  while(srvc->convs) +    mwConversation_free(srvc->convs->data); + +  mwService_stopped(MW_SERVICE(srvc)); +} + + +struct mwServiceIm *mwServiceIm_new(struct mwSession *session, +				    struct mwImHandler *hndl) { + +  struct mwServiceIm *srvc_im; +  struct mwService *srvc; + +  g_return_val_if_fail(session != NULL, NULL); +  g_return_val_if_fail(hndl != NULL, NULL); + +  srvc_im = g_new0(struct mwServiceIm, 1); +  srvc = MW_SERVICE(srvc_im); + +  mwService_init(srvc, session, mwService_IM); +  srvc->recv_create = recv_channelCreate; +  srvc->recv_accept = recv_channelAccept; +  srvc->recv_destroy = recv_channelDestroy; +  srvc->recv = recv; +  srvc->clear = (mwService_funcClear) clear; +  srvc->get_name = name; +  srvc->get_desc = desc; +  srvc->start = start; +  srvc->stop = (mwService_funcStop) stop; + +  srvc_im->features = mwImClient_PLAIN; +  srvc_im->handler = hndl; + +  return srvc_im; +} + + +struct mwImHandler *mwServiceIm_getHandler(struct mwServiceIm *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return srvc->handler; +} + + +/// Miranda NG adaptation start - new method +struct mwService *mwServiceIm_getService(struct mwServiceIm *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return &(srvc->service); +} +/// Miranda NG adaptation end + + +gboolean mwServiceIm_supports(struct mwServiceIm *srvc, +			      enum mwImSendType type) { + +  g_return_val_if_fail(srvc != NULL, FALSE); + +  switch(type) { +  case mwImSend_PLAIN: +  case mwImSend_TYPING: +    return TRUE; + +  case mwImSend_SUBJECT: +  case mwImSend_HTML: +  case mwImSend_MIME: +  case mwImSend_TIMESTAMP: +    return srvc->features == mwImClient_NOTESBUDDY; + +  default: +    return FALSE; +  } +} + + +void mwServiceIm_setClientType(struct mwServiceIm *srvc, +			       enum mwImClientType type) { + +  g_return_if_fail(srvc != NULL); +  srvc->features = type; +} + + +enum mwImClientType mwServiceIm_getClientType(struct mwServiceIm *srvc) { +  g_return_val_if_fail(srvc != NULL, mwImClient_UNKNOWN); +  return srvc->features; +} + + +static int convo_send_data(struct mwConversation *conv, +			   guint32 type, guint32 subtype, +			   struct mwOpaque *data) { +  struct mwPutBuffer *b; +  struct mwOpaque o; +  struct mwChannel *chan; +  int ret; + +  chan = conv->channel; +  g_return_val_if_fail(chan != NULL, -1); + +  b = mwPutBuffer_new(); + +  guint32_put(b, mwIm_DATA); +  guint32_put(b, type); +  guint32_put(b, subtype); +  mwOpaque_put(b, data); + +  mwPutBuffer_finalize(&o, b); + +  ret = mwChannel_sendEncrypted(chan, msg_MESSAGE, &o, !conv->ext_id); +  mwOpaque_clear(&o); + +  return ret; +} + + +static int convo_send_multi_start(struct mwConversation *conv) { +  return convo_send_data(conv, mwImData_MULTI_START, 0x00, NULL); +} + + +static int convo_send_multi_stop(struct mwConversation *conv) { +  return convo_send_data(conv, mwImData_MULTI_STOP, 0x00, NULL); +} + + +/* breaks up a large message into segments, sends a start_segment +   message, then sends each segment in turn, then sends a stop_segment +   message */ +static int +convo_sendSegmented(struct mwConversation *conv, const char *message, +		    int (*send)(struct mwConversation *conv, +				const char *msg)) { +  char *buf = (char *) message; +  gsize len; +  int ret = 0; + +  len = strlen(buf); +  ret = convo_send_multi_start(conv); + +  while(len && !ret) { +    char tail; +    gsize seg; + +    seg = BREAKUP; +    if(len < BREAKUP) +      seg = len; + +    /* temporarily NUL-terminate this segment */ +    tail = buf[seg]; +    buf[seg] = 0x00; + +    ret = send(conv, buf); + +    /* restore this segment */ +    buf[seg] = tail; +     +    buf += seg; +    len -= seg; +  } + +  if(! ret) +    ret = convo_send_multi_stop(conv); + +  return ret; +} + + +static int convo_sendText(struct mwConversation *conv, const char *text) { +  struct mwPutBuffer *b; +  struct mwOpaque o; +  int ret; +   +  b = mwPutBuffer_new(); + +  guint32_put(b, mwIm_TEXT); +  mwString_put(b, text); + +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_sendEncrypted(conv->channel, msg_MESSAGE, &o, !conv->ext_id); +  mwOpaque_clear(&o); + +  return ret; +} + + +static int convo_sendTyping(struct mwConversation *conv, gboolean typing) { +  return convo_send_data(conv, mwImData_TYPING, !typing, NULL); +} + + +static int convo_sendSubject(struct mwConversation *conv, +			     const char *subject) { +  struct mwOpaque o; + +  o.len = strlen(subject); +  o.data = (guchar *) subject; + +  return convo_send_data(conv, mwImData_SUBJECT, 0x00, &o); +} + + +static int convo_sendHtml(struct mwConversation *conv, const char *html) { +  struct mwOpaque o; + +  o.len = strlen(html); +  o.data = (guchar *) html; + +  if(o.len > BREAKUP) { +    return convo_sendSegmented(conv, html, convo_sendHtml); +  } else { +    return convo_send_data(conv, mwImData_HTML, 0x00, &o); +  } +} + + +static int convo_sendMime(struct mwConversation *conv, const char *mime) { +  struct mwOpaque o; + +  o.len = strlen(mime); +  o.data = (guchar *) mime; + +  if(o.len > BREAKUP) { +    return convo_sendSegmented(conv, mime, convo_sendMime); +  } else { +    return convo_send_data(conv, mwImData_MIME, 0x00, &o); +  } +} + + +int mwConversation_send(struct mwConversation *conv, enum mwImSendType type, +			gconstpointer msg) { + +  g_return_val_if_fail(conv != NULL, -1); +  g_return_val_if_fail(mwConversation_isOpen(conv), -1); +  g_return_val_if_fail(conv->channel != NULL, -1); + +  switch(type) { +  case mwImSend_PLAIN: +    return convo_sendText(conv, msg); +  case mwImSend_TYPING: +    return convo_sendTyping(conv, GPOINTER_TO_INT(msg)); +  case mwImSend_SUBJECT: +    return convo_sendSubject(conv, msg); +  case mwImSend_HTML: +    return convo_sendHtml(conv, msg); +  case mwImSend_MIME: +    return convo_sendMime(conv, msg); + +  default: +    g_warning("unsupported IM Send Type, 0x%x", type); +    return -1; +  } +} + + +enum mwConversationState mwConversation_getState(struct mwConversation *conv) { +  g_return_val_if_fail(conv != NULL, mwConversation_UNKNOWN); +  return conv->state; +} + + +struct mwServiceIm *mwConversation_getService(struct mwConversation *conv) { +  g_return_val_if_fail(conv != NULL, NULL); +  return conv->service; +} + + +gboolean mwConversation_supports(struct mwConversation *conv, +				 enum mwImSendType type) { +  g_return_val_if_fail(conv != NULL, FALSE); + +  switch(type) { +  case mwImSend_PLAIN: +  case mwImSend_TYPING: +    return TRUE; + +  case mwImSend_SUBJECT: +  case mwImSend_HTML: +  case mwImSend_MIME: +    return conv->features == mwImClient_NOTESBUDDY; + +  default: +    return FALSE; +  } +} + + +enum mwImClientType +mwConversation_getClientType(struct mwConversation *conv) { +  g_return_val_if_fail(conv != NULL, mwImClient_UNKNOWN); +  return conv->features; +} + + +struct mwIdBlock *mwConversation_getTarget(struct mwConversation *conv) { +  g_return_val_if_fail(conv != NULL, NULL); +  return &conv->target; +} + + +struct mwLoginInfo *mwConversation_getTargetInfo(struct mwConversation *conv) { +  g_return_val_if_fail(conv != NULL, NULL); +  g_return_val_if_fail(conv->channel != NULL, NULL); +  return mwChannel_getUser(conv->channel); +} + + +void mwConversation_setClientData(struct mwConversation *conv, +				  gpointer data, GDestroyNotify clean) { +  g_return_if_fail(conv != NULL); +  mw_datum_set(&conv->client_data, data, clean); +} + + +gpointer mwConversation_getClientData(struct mwConversation *conv) { +  g_return_val_if_fail(conv != NULL, NULL); +  return mw_datum_get(&conv->client_data); +} + + +void mwConversation_removeClientData(struct mwConversation *conv) { +  g_return_if_fail(conv != NULL); +  mw_datum_clear(&conv->client_data); +} + + +void mwConversation_close(struct mwConversation *conv, guint32 reason) { +  struct mwServiceIm *srvc; +  struct mwImHandler *h; + +  g_return_if_fail(conv != NULL); + +  convo_set_state(conv, mwConversation_CLOSED); + +  srvc = conv->service; +  g_return_if_fail(srvc != NULL); + +  h = srvc->handler; +  if(h && h->conversation_closed) +    h->conversation_closed(conv, reason); + +  if(conv->channel) { +    mwChannel_destroy(conv->channel, reason, NULL); +    conv->channel = NULL; +  } +} + + +void mwConversation_free(struct mwConversation *conv) { +  g_return_if_fail(conv != NULL); + +  if(! mwConversation_isClosed(conv)) +    mwConversation_close(conv, ERR_SUCCESS); + +  convo_free(conv); +} + diff --git a/protocols/Sametime/src/meanwhile/src/srvc_place.c b/protocols/Sametime/src/meanwhile/src/srvc_place.c new file mode 100644 index 0000000000..5029dffbb8 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/srvc_place.c @@ -0,0 +1,1089 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <glib.h> +#include <glib/ghash.h> +#include <glib/glist.h> + +#include <stdio.h> +#include <stdlib.h> + +#include "mw_channel.h" +#include "mw_common.h" +#include "mw_debug.h" +#include "mw_error.h" +#include "mw_message.h" +#include "mw_service.h" +#include "mw_session.h" +#include "mw_srvc_place.h" +#include "mw_util.h" + + +#define PROTOCOL_TYPE  0x00 +#define PROTOCOL_VER   0x05 + + +enum incoming_msg { +  msg_in_JOIN_RESPONSE  = 0x0000,  /* ? */ +  msg_in_INFO           = 0x0002, +  msg_in_MESSAGE        = 0x0004, +  msg_in_SECTION        = 0x0014,  /* see in_section_subtype */ +  msg_in_UNKNOWNa       = 0x0015, +}; + + +enum in_section_subtype { +  msg_in_SECTION_LIST  = 0x0000,  /* list of section members */ +  msg_in_SECTION_PEER  = 0x0001,  /* see in_section_peer_subtye */ +  msg_in_SECTION_PART  = 0x0003, +}; + + +enum in_section_peer_subtype { +  msg_in_SECTION_PEER_JOIN        = 0x0000, +  msg_in_SECTION_PEER_PART        = 0x0001,  /* after msg_in_SECTION_PART */ +  msg_in_SECTION_PEER_CLEAR_ATTR  = 0x0003, +  msg_in_SECTION_PEER_SET_ATTR    = 0x0004, +}; + + +enum outgoing_msg { +  msg_out_JOIN_PLACE  = 0x0000,  /* ? */ +  msg_out_PEER_INFO   = 0x0002,  /* ? */ +  msg_out_MESSAGE     = 0x0003, +  msg_out_OLD_INVITE  = 0x0005,  /* old-style conf. invitation */ +  msg_out_SET_ATTR    = 0x000a, +  msg_out_CLEAR_ATTR  = 0x000b, +  msg_out_SECTION     = 0x0014,  /* see out_section_subtype */ +  msg_out_UNKNOWNb    = 0x001e,  /* ? maybe enter stage ? */ +}; + + +enum out_section_subtype { +  msg_out_SECTION_LIST  = 0x0002,  /* req list of members */ +  msg_out_SECTION_PART  = 0x0003, +}; + + +/* +  : allocate section +  : state = NEW + +  : create channel +  : state = PENDING + +  : channel accepted +  : msg_out_JOIN_PLACE  (maybe create?) +  : state = JOINING + +  : msg_in_JOIN_RESPONSE (contains our place member ID and section ID) +  : msg_in_INFO (for place, not peer) +  : state = JOINED + +  : msg_out_SECTION_LIST (asking for all sections) (optional) +  : msg_in_SECTION_LIST (listing all sections, as requested above) + +  : msg_out_PEER_INFO (with our place member ID) (optional) +  : msg_in_INFO (peer info as requested above) + +  : msg_out_SECTION_LIST (with our section ID) (sorta optional) +  : msg_in_SECTION_LIST (section listing as requested above) + +  : msg_out_UNKNOWNb +  : msg_in_SECTION_PEER_JOINED (empty, with our place member ID) +  : state = OPEN + +  : stuff... (invites, joins, parts, messages, attr) + +  : state = CLOSING +  : msg_out_SECTION_PART +  : destroy channel +  : deallocate section +*/ + + +struct mwServicePlace { +  struct mwService service; +  struct mwPlaceHandler *handler; +  GList *places; +}; + + +enum mwPlaceState { +  mwPlace_NEW, +  mwPlace_PENDING, +  mwPlace_JOINING, +  mwPlace_JOINED, +  mwPlace_OPEN, +  mwPlace_CLOSING, +  mwPlace_ERROR, +  mwPlace_UNKNOWN, +}; + + +struct mwPlace { +  struct mwServicePlace *service; + +  enum mwPlaceState state; +  struct mwChannel *channel; + +  char *name; +  char *title; +  GHashTable *members;  /* mapping of member ID: place_member */ +  guint32 our_id;       /* our member ID */ +  guint32 section;      /* the section we're using */ + +  guint32 requests;     /* counter for requests */ + +  struct mw_datum client_data; +}; + + +struct place_member { +  guint32 place_id; +  guint16 member_type; +  struct mwIdBlock idb; +  char *login_id; +  char *name; +  guint16 login_type; +  guint32 unknown_a; +  guint32 unknown_b; +}; + + +#define GET_MEMBER(place, id) \ +  (g_hash_table_lookup(place->members, GUINT_TO_POINTER(id))) + + +#define PUT_MEMBER(place, member) \ +  (g_hash_table_insert(place->members, \ +                       GUINT_TO_POINTER(member->place_id), member)) + + +#define REMOVE_MEMBER_ID(place, id) \ +  (g_hash_table_remove(place->members, GUINT_TO_POINTER(id))) + + +#define REMOVE_MEMBER(place, member) \ +  REMOVE_MEMBER_ID(place, member->place_id) + + +static void member_free(struct place_member *p) { +  mwIdBlock_clear(&p->idb); +  g_free(p->login_id); +  g_free(p->name); +  g_free(p); +} + +/// Miranda NG adaptation start - MSVC +/// __attribute__((used)) +/// Miranda NG adaptation end +static const struct mwLoginInfo * +member_as_login_info(struct place_member *p) { +  static struct mwLoginInfo li; +   +  li.login_id = p->login_id; +  li.type = p->login_type; +  li.user_id = p->idb.user; +  li.user_name = p->name; +  li.community = p->idb.community; +  li.full = FALSE; + +  return &li; +} + + +static const char *place_state_str(enum mwPlaceState s) { +  switch(s) { +  case mwPlace_NEW:      return "new"; +  case mwPlace_PENDING:  return "pending"; +  case mwPlace_JOINING:  return "joining"; +  case mwPlace_JOINED:   return "joined"; +  case mwPlace_OPEN:     return "open"; +  case mwPlace_CLOSING:  return "closing"; +  case mwPlace_ERROR:    return "error"; + +  case mwPlace_UNKNOWN:  /* fall-through */ +  default:               return "UNKNOWN"; +  } +} + + +static void place_state(struct mwPlace *place, enum mwPlaceState s) { +  g_return_if_fail(place != NULL); +   +  if(place->state == s) return; + +  place->state = s; +  g_message("place %s state: %s", NSTR(place->name), place_state_str(s)); +} + + +static void place_free(struct mwPlace *place) { +  struct mwServicePlace *srvc; + +  if(! place) return; +   +  srvc = place->service; +  g_return_if_fail(srvc != NULL); + +  srvc->places = g_list_remove_all(srvc->places, place); + +  mw_datum_clear(&place->client_data); + +  g_hash_table_destroy(place->members); + +  g_free(place->name); +  g_free(place->title); +  g_free(place); +} + + +static int recv_JOIN_RESPONSE(struct mwPlace *place, +			      struct mwGetBuffer *b) { +   +  int ret = 0; +  guint32 our_id, section; + +  guint32_get(b, &our_id); +  guint32_get(b, §ion); + +  place->our_id = our_id; +  place->section = section; + +  return ret; +} + + +static int send_SECTION_LIST(struct mwPlace *place, guint32 section) { +  int ret = 0; +  struct mwOpaque o = {0, 0}; +  struct mwPutBuffer *b; + +  b = mwPutBuffer_new(); +  guint16_put(b, msg_out_SECTION_LIST); +  guint32_put(b, section); +  gboolean_put(b, FALSE); +  guint32_put(b, ++place->requests); +  mwPutBuffer_finalize(&o, b); + +  ret = mwChannel_send(place->channel, msg_out_SECTION, &o); +  mwOpaque_clear(&o); + +  return ret; +} + + +static int recv_INFO(struct mwPlace *place, +		     struct mwGetBuffer *b) { + +  int ret = 0; +  guint32 skip = 0; +  guint32 section = 0; + +  guint32_get(b, &skip); +  guint32_get(b, §ion); +  mwGetBuffer_advance(b, skip); + +  if(! section) { +    /* this is a place info rather than member info */ +    if(place->title) g_free(place->title); +    mwGetBuffer_advance(b, 2); +    mwString_get(b, &place->title); + +    place_state(place, mwPlace_JOINED); +    ret = send_SECTION_LIST(place, place->section); +  } + +  return ret; +} + + +static int recv_MESSAGE(struct mwPlace *place, +			struct mwGetBuffer *b) { + +  struct mwServicePlace *srvc; +  guint32 pm_id; +  guint32 unkn_a, unkn_b, ign; +  struct place_member *pm; +  char *msg = NULL; +  int ret = 0; + +  srvc = place->service; + +  /* no messages before becoming fully open, please */ +  g_return_val_if_fail(place->state == mwPlace_OPEN, -1); + +  /* regarding unkn_a and unkn_b: + +     they're probably a section indicator and a message count, I'm +     just not sure which is which. Until this implementation supports +     place sections in the API, it really doesn't matter. */ +   +  guint32_get(b, &pm_id); +  pm = GET_MEMBER(place, pm_id); +  g_return_val_if_fail(pm != NULL, -1); + +  guint32_get(b, &unkn_a); +  guint32_get(b, &ign);     /* actually an opaque length */ +   +  if(! ign) return ret; + +  guint32_get(b, &unkn_b); +  mwString_get(b, &msg); + +  if(srvc->handler && srvc->handler->message) +    srvc->handler->message(place, &pm->idb, msg); + +  g_free(msg); + +  return ret; +} + + +static void place_opened(struct mwPlace *place) { +    struct mwServicePlace *srvc; + +    place_state(place, mwPlace_OPEN); + +    srvc = place->service; +    if(srvc->handler && srvc->handler->opened) +      srvc->handler->opened(place); +} + + +static int recv_SECTION_PEER_JOIN(struct mwPlace *place, +				  struct mwGetBuffer *b) { +  struct mwServicePlace *srvc; +  struct place_member *pm; +  guint32 section; +  int ret = 0; + +  srvc = place->service; + +  guint32_get(b, §ion); +  if(! section) { +    /// Miranda NG adaptation start - MSVC +    ///g_info("SECTION_PEER_JOIN with section 0x00"); +    g_message("SECTION_PEER_JOIN with section 0x00"); +    /// Miranda NG adaptation end +    return 0; +  } + +  mwGetBuffer_advance(b, 4); + +  pm = g_new0(struct place_member, 1); +  guint32_get(b, &pm->place_id); +  guint16_get(b, &pm->member_type); +  mwIdBlock_get(b, &pm->idb); +  mwString_get(b, &pm->login_id); +  mwString_get(b, &pm->name); +  guint16_get(b, &pm->login_type); +  guint32_get(b, &pm->unknown_a); +  guint32_get(b, &pm->unknown_b); + +  PUT_MEMBER(place, pm); +  if(srvc->handler && srvc->handler->peerJoined) +    srvc->handler->peerJoined(place, &pm->idb); + +  if(pm->place_id == place->our_id) +    place_opened(place); + +  return ret; +} + + +static int recv_SECTION_PEER_PART(struct mwPlace *place, +				  struct mwGetBuffer *b) { +  struct mwServicePlace *srvc; +  int ret = 0; +  guint32 section, id; +  struct place_member *pm; + +  srvc = place->service; + +  guint32_get(b, §ion); +  g_return_val_if_fail(section == place->section, 0); + +  guint32_get(b, &id); +  pm = GET_MEMBER(place, id); + +  /* SECTION_PART may have been called already */ +  if(! pm) return 0; + +  if(srvc->handler && srvc->handler->peerParted) +    srvc->handler->peerParted(place, &pm->idb); + +  REMOVE_MEMBER(place, pm); + +  return ret; +} + + +static int recv_SECTION_PEER_CLEAR_ATTR(struct mwPlace *place, +					struct mwGetBuffer *b) { +  struct mwServicePlace *srvc; +  int ret = 0; +  guint32 id, attr; +  struct place_member *pm; +   +  srvc = place->service; + +  guint32_get(b, &id); +  guint32_get(b, &attr); + +  pm = GET_MEMBER(place, id); +  g_return_val_if_fail(pm != NULL, -1); + +  if(srvc->handler && srvc->handler->peerUnsetAttribute) +    srvc->handler->peerUnsetAttribute(place, &pm->idb, attr); + +  return ret; +} + + +static int recv_SECTION_PEER_SET_ATTR(struct mwPlace *place, +				      struct mwGetBuffer *b) { +  struct mwServicePlace *srvc; +  int ret = 0; +  guint32 id, attr; +  struct mwOpaque o = {0,0}; +  struct place_member *pm; +   +  srvc = place->service; + +  guint32_get(b, &id); +  mwGetBuffer_advance(b, 4); +  mwOpaque_get(b, &o); +  mwGetBuffer_advance(b, 4); +  guint32_get(b, &attr); + +  pm = GET_MEMBER(place, id); +  g_return_val_if_fail(pm != NULL, -1); + +  if(srvc->handler && srvc->handler->peerSetAttribute) +    srvc->handler->peerSetAttribute(place, &pm->idb, attr, &o); + +  mwOpaque_clear(&o); + +  return ret; +} + + +static int recv_SECTION_PEER(struct mwPlace *place, +			      struct mwGetBuffer *b) { +  guint16 subtype; +  int res; + +  guint16_get(b, &subtype); + +  g_return_val_if_fail(! mwGetBuffer_error(b), -1); + +  switch(subtype) { +  case msg_in_SECTION_PEER_JOIN: +    res = recv_SECTION_PEER_JOIN(place, b); +    break; + +  case msg_in_SECTION_PEER_PART: +    res = recv_SECTION_PEER_PART(place, b); +    break; + +  case msg_in_SECTION_PEER_CLEAR_ATTR: +    res = recv_SECTION_PEER_CLEAR_ATTR(place, b); +    break; + +  case msg_in_SECTION_PEER_SET_ATTR: +    res = recv_SECTION_PEER_SET_ATTR(place, b); +    break; + +  default: +    res = -1; +  } + +  return res; +} + + +static int recv_SECTION_LIST(struct mwPlace *place, +			     struct mwGetBuffer *b) { +  int ret = 0; +  guint32 sec, count; + +  mwGetBuffer_advance(b, 4); +  guint32_get(b, &sec); + +  g_return_val_if_fail(sec == place->section, -1); + +  mwGetBuffer_advance(b, 8); +  guint32_get(b, &count); +  mwGetBuffer_advance(b, 8); + +  while(count--) { +    struct place_member *m; + +    m = g_new0(struct place_member, 1); +    mwGetBuffer_advance(b, 4); +    guint32_get(b, &m->place_id); +    guint16_get(b, &m->member_type); +    mwIdBlock_get(b, &m->idb); +    mwString_get(b, &m->login_id); +    mwString_get(b, &m->name); +    guint16_get(b, &m->login_type); +    guint32_get(b, &m->unknown_a); +    guint32_get(b, &m->unknown_b); + +    PUT_MEMBER(place, m); +  } + +  if(place->state != mwPlace_OPEN) +    place_opened(place); + +  return ret; +} + + +static int recv_SECTION_PART(struct mwPlace *place, +			     struct mwGetBuffer *b) { +  /* look up user in place +     remove user from place +     trigger event */ + +  struct mwServicePlace *srvc; +  guint32 pm_id; +  struct place_member *pm; + +  srvc = place->service; + +  guint32_get(b, &pm_id); +  pm = GET_MEMBER(place, pm_id); + +  /* SECTION_PEER_PART may have been called already */ +  if(! pm) return 0; + +  if(srvc->handler && srvc->handler->peerParted) +    srvc->handler->peerParted(place, &pm->idb); + +  REMOVE_MEMBER(place, pm); + +  return 0; +} + + +static int recv_SECTION(struct mwPlace *place, struct mwGetBuffer *b) { +  guint16 subtype; +  int res; + +  guint16_get(b, &subtype); + +  g_return_val_if_fail(! mwGetBuffer_error(b), -1); + +  switch(subtype) { +  case msg_in_SECTION_LIST: +    res = recv_SECTION_LIST(place, b); +    break; + +  case msg_in_SECTION_PEER: +    res = recv_SECTION_PEER(place, b); +    break; + +  case msg_in_SECTION_PART: +    res = recv_SECTION_PART(place, b); +    break; + +  default: +    res = -1; +  } + +  return res; +} + + +static int recv_UNKNOWNa(struct mwPlace *place, struct mwGetBuffer *b) { +  int res = 0; + +  if(place->state == mwPlace_JOINING) { +    ; +    /* place_state(place, mwPlace_JOINED); +       res = send_SECTION_LIST(place, place->section); */ +   +  } else if(place->state == mwPlace_JOINED) { +    ; +    /* if(GET_MEMBER(place, place->our_id)) +       place_opened(place); */ +  } + +  return res; +} + + +static void recv(struct mwService *service, struct mwChannel *chan, +		 guint16 type, struct mwOpaque *data) { + +  struct mwPlace *place; +  struct mwGetBuffer *b; +  int res = 0; + +  place = mwChannel_getServiceData(chan); +  g_return_if_fail(place != NULL); + +  b = mwGetBuffer_wrap(data); +  switch(type) { +  case msg_in_JOIN_RESPONSE: +    res = recv_JOIN_RESPONSE(place, b); +    break; + +  case msg_in_INFO: +    res = recv_INFO(place, b); +    break; + +  case msg_in_MESSAGE: +    res = recv_MESSAGE(place, b); +    break; + +  case msg_in_SECTION: +    res = recv_SECTION(place, b); +    break; + +  case msg_in_UNKNOWNa: +    res = recv_UNKNOWNa(place, b); +    break; + +  default: +    mw_mailme_opaque(data, "Received unknown message type 0x%x on place %s", +		     type, NSTR(place->name)); +  } + +  if(res) { +    mw_mailme_opaque(data, "Troubling parsing message type 0x0%x on place %s", +		     type, NSTR(place->name)); +  } + +  mwGetBuffer_free(b); +} + + +static void stop(struct mwServicePlace *srvc) { +  while(srvc->places) +    mwPlace_destroy(srvc->places->data, ERR_SUCCESS); + +  mwService_stopped(MW_SERVICE(srvc)); +} + + +static int send_JOIN_PLACE(struct mwPlace *place) { +  struct mwOpaque o = {0, 0}; +  struct mwPutBuffer *b; +  int ret; + +  b = mwPutBuffer_new(); +  gboolean_put(b, FALSE); +  guint16_put(b, 0x01); +  guint16_put(b, 0x02); /* 0x01 */ +  guint16_put(b, 0x01); /* 0x00 */ + +  mwPutBuffer_finalize(&o, b); + +  ret = mwChannel_send(place->channel, msg_out_JOIN_PLACE, &o); + +  mwOpaque_clear(&o); + +  if(ret) { +    place_state(place, mwPlace_ERROR); +  } else { +    place_state(place, mwPlace_JOINING); +  } + +  return ret; +} + + +static void recv_channelAccept(struct mwService *service, +			       struct mwChannel *chan, +			       struct mwMsgChannelAccept *msg) { +  struct mwServicePlace *srvc; +  struct mwPlace *place; +  int res; + +  srvc = (struct mwServicePlace *) service; +  g_return_if_fail(srvc != NULL); + +  place = mwChannel_getServiceData(chan); +  g_return_if_fail(place != NULL); + +  res = send_JOIN_PLACE(place); +} + + +static void recv_channelDestroy(struct mwService *service, +				struct mwChannel *chan, +				struct mwMsgChannelDestroy *msg) { +  struct mwServicePlace *srvc; +  struct mwPlace *place; + +  srvc = (struct mwServicePlace *) service; +  g_return_if_fail(srvc != NULL); + +  place = mwChannel_getServiceData(chan); +  g_return_if_fail(place != NULL); + +  place_state(place, mwPlace_ERROR); + +  place->channel = NULL; + +  if(srvc->handler && srvc->handler->closed) +    srvc->handler->closed(place, msg->reason);   + +  mwPlace_destroy(place, msg->reason); +} + + +static void clear(struct mwServicePlace *srvc) { + +  if(srvc->handler && srvc->handler->clear) +    srvc->handler->clear(srvc); + +  while(srvc->places) +    place_free(srvc->places->data); +} + + +static const char *get_name(struct mwService *srvc) { +  return "Places Conferencing"; +} + + +static const char *get_desc(struct mwService *srvc) { +  return "Barebones conferencing via Places"; +} + + +struct mwServicePlace * +mwServicePlace_new(struct mwSession *session, +		   struct mwPlaceHandler *handler) { + +  struct mwServicePlace *srvc_place; +  struct mwService *srvc; + +  g_return_val_if_fail(session != NULL, NULL); +  g_return_val_if_fail(handler != NULL, NULL); + +  srvc_place = g_new0(struct mwServicePlace, 1); +  srvc_place->handler = handler; + +  srvc = MW_SERVICE(srvc_place); +  mwService_init(srvc, session, mwService_PLACE); +  srvc->start = NULL; +  srvc->stop = (mwService_funcStop) stop; +  srvc->recv_create = NULL; +  srvc->recv_accept = recv_channelAccept; +  srvc->recv_destroy = recv_channelDestroy; +  srvc->recv = recv; +  srvc->clear = (mwService_funcClear) clear; +  srvc->get_name = get_name; +  srvc->get_desc = get_desc; + +  return srvc_place; +} + + +struct mwPlaceHandler * +mwServicePlace_getHandler(struct mwServicePlace *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return srvc->handler; +} + + +const GList *mwServicePlace_getPlaces(struct mwServicePlace *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return srvc->places; +} + + +struct mwPlace *mwPlace_new(struct mwServicePlace *srvc, +			    const char *name, const char *title) { +  struct mwPlace *place; + +  g_return_val_if_fail(srvc != NULL, NULL); +   +  place = g_new0(struct mwPlace, 1); +  place->service = srvc; +  place->name = g_strdup(name); +  place->title = g_strdup(title); +  place->state = mwPlace_NEW; + +  place->members = g_hash_table_new_full(g_direct_hash, g_direct_equal, +					 NULL, (GDestroyNotify) member_free); + +  srvc->places = g_list_prepend(srvc->places, place); +   +  return place; +} + + +struct mwServicePlace *mwPlace_getService(struct mwPlace *place) { +  g_return_val_if_fail(place != NULL, NULL); +  return place->service; +} + + +static char *place_generate_name(const char *user) { +  /// Miranda NG adaptation start - MSVC +  ///guint a, b; +  guint a; +  guint64 b; +  /// Miranda NG adaptation end +  char *ret; +   +  user = user? user: "meanwhile"; + +  srand(clock() + rand()); +  a = ((rand() & 0xff) << 8) | (rand() & 0xff); +  b = time(NULL); + +  /// Miranda NG adaptation start - MSVC +  ///ret = g_strdup_printf("%s(%08x,%04x)", user, b, a); +  ret = g_strdup_printf("%s(%I64u,%04x)", user, b, a); +  /// Miranda NG adaptation end +  g_debug("generated random conference name: '%s'", ret); +  return ret; +} + + +const char *mwPlace_getName(struct mwPlace *place) { +  g_return_val_if_fail(place != NULL, NULL); + +  if(! place->name) { +    struct mwSession *session; +    struct mwLoginInfo *li; + +    session = mwService_getSession(MW_SERVICE(place->service)); +    li = mwSession_getLoginInfo(session); + +    place->name = place_generate_name(li? li->user_id: NULL); +  } + +  return place->name; +} + + +static char *place_generate_title(const char *user) { +  char *ret; +   +  user = user? user: "Meanwhile"; +  ret = g_strdup_printf("%s's Conference", user); +  g_debug("generated conference title: %s", ret); + +  return ret; +} + + +const char *mwPlace_getTitle(struct mwPlace *place) { +  g_return_val_if_fail(place != NULL, NULL); + +  if(! place->title) { +    struct mwSession *session; +    struct mwLoginInfo *li; + +    session = mwService_getSession(MW_SERVICE(place->service)); +    li = mwSession_getLoginInfo(session); + +    place->title = place_generate_title(li? li->user_name: NULL); +  } + +  return place->title; +} + + +int mwPlace_open(struct mwPlace *p) { +  struct mwSession *session; +  struct mwChannelSet *cs; +  struct mwChannel *chan; +  struct mwPutBuffer *b; +  int ret; + +  g_return_val_if_fail(p != NULL, -1); +  g_return_val_if_fail(p->service != NULL, -1); + +  session = mwService_getSession(MW_SERVICE(p->service)); +  g_return_val_if_fail(session != NULL, -1); + +  cs = mwSession_getChannels(session); +  g_return_val_if_fail(cs != NULL, -1); + +  chan = mwChannel_newOutgoing(cs); +  mwChannel_setService(chan, MW_SERVICE(p->service)); +  mwChannel_setProtoType(chan, PROTOCOL_TYPE); +  mwChannel_setProtoVer(chan, PROTOCOL_VER); + +  mwChannel_populateSupportedCipherInstances(chan); + +  b = mwPutBuffer_new(); +  mwString_put(b, mwPlace_getName(p)); +  mwString_put(b, mwPlace_getTitle(p)); +  guint32_put(b, 0x00); /* ? */ + +  mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b); + +  ret = mwChannel_create(chan); +  if(ret) { +    place_state(p, mwPlace_ERROR); +  } else { +    place_state(p, mwPlace_PENDING); +    p->channel = chan; +    mwChannel_setServiceData(chan, p, NULL); +  } + +  return ret; +} + + +int mwPlace_destroy(struct mwPlace *p, guint32 code) { +  int ret = 0; + +  place_state(p, mwPlace_CLOSING); + +  if(p->channel) { +    ret = mwChannel_destroy(p->channel, code, NULL); +    p->channel = NULL; +  } + +  place_free(p); + +  return ret; +} + + +GList *mwPlace_getMembers(struct mwPlace *place) { +  GList *l, *ll; + +  g_return_val_if_fail(place != NULL, NULL); +  g_return_val_if_fail(place->members != NULL, NULL); + +  ll = map_collect_values(place->members); +  for(l = ll; l; l = l->next) { +    struct place_member *pm = l->data; +    l->data = &pm->idb; +    /// Miranda NG adaptation start - MSVC +    //g_info("collected member %u: %s, %s", pm->place_id, +    //   NSTR(pm->idb.user), NSTR(pm->idb.community)); +    g_message("collected member %u: %s, %s", pm->place_id, NSTR(pm->idb.user), NSTR(pm->idb.community)); +    /// Miranda NG adaptation end +  } + +  return ll; +} + + +int mwPlace_sendText(struct mwPlace *place, const char *msg) { +  struct mwOpaque o = {0,0}; +  struct mwPutBuffer *b; +  int ret; + +  b = mwPutBuffer_new(); +  guint32_put(b, 0x01);  /* probably a message type */ +  mwString_put(b, msg); +  mwPutBuffer_finalize(&o, b); + +  b = mwPutBuffer_new(); +  guint32_put(b, place->section); +  mwOpaque_put(b, &o); +  mwOpaque_clear(&o); +  mwPutBuffer_finalize(&o, b); + +  ret = mwChannel_send(place->channel, msg_out_MESSAGE, &o); +  mwOpaque_clear(&o); +  return ret; +} + + +int mwPlace_legacyInvite(struct mwPlace *place, +			 struct mwIdBlock *idb, +			 const char *message) { + +  struct mwOpaque o = {0,0}; +  struct mwPutBuffer *b; +  int ret; + +  b = mwPutBuffer_new(); +  mwIdBlock_put(b, idb); +  mwString_put(b, idb->user); +  mwString_put(b, idb->user); +  mwString_put(b, message); +  gboolean_put(b, FALSE); +  mwPutBuffer_finalize(&o, b); + +  ret = mwChannel_send(place->channel, msg_out_OLD_INVITE, &o); +  mwOpaque_clear(&o); +  return ret; +} + + +int mwPlace_setAttribute(struct mwPlace *place, guint32 attrib, +			 struct mwOpaque *data) { + +  struct mwOpaque o = {0,0}; +  struct mwPutBuffer *b; +  int ret; + +  b = mwPutBuffer_new(); +  guint32_put(b, place->our_id); +  guint32_put(b, 0x00); +  guint32_put(b, attrib); +  mwOpaque_put(b, data); +   +  ret = mwChannel_send(place->channel, msg_out_SET_ATTR, &o); +  mwOpaque_clear(&o); +  return ret; +} + + +int mwPlace_unsetAttribute(struct mwPlace *place, guint32 attrib) { +  struct mwOpaque o = {0,0}; +  struct mwPutBuffer *b; +  int ret; + +  b = mwPutBuffer_new(); +  guint32_put(b, place->our_id); +  guint32_put(b, attrib); +   +  ret = mwChannel_send(place->channel, msg_out_SET_ATTR, &o); +  mwOpaque_clear(&o); +  return ret; +} + + +void mwPlace_setClientData(struct mwPlace *place, +			   gpointer data, GDestroyNotify clear) { + +  g_return_if_fail(place != NULL); +  mw_datum_set(&place->client_data, data, clear); +} + + +gpointer mwPlace_getClientData(struct mwPlace *place) { +  g_return_val_if_fail(place != NULL, NULL); +  return mw_datum_get(&place->client_data); +} + + +void mwPlace_removeClientData(struct mwPlace *place) { +  g_return_if_fail(place != NULL); +  mw_datum_clear(&place->client_data); +} diff --git a/protocols/Sametime/src/meanwhile/src/srvc_resolve.c b/protocols/Sametime/src/meanwhile/src/srvc_resolve.c new file mode 100644 index 0000000000..bb4c536be8 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/srvc_resolve.c @@ -0,0 +1,396 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <glib/ghash.h> + +#include "mw_channel.h" +#include "mw_common.h" +#include "mw_debug.h" +#include "mw_error.h" +#include "mw_service.h" +#include "mw_session.h" +#include "mw_srvc_resolve.h" + + +#define PROTOCOL_TYPE  0x00000015 +#define PROTOCOL_VER   0x00000000 + + +/** oddly, there is only one message type in this service */ +#define RESOLVE_ACTION  0x02 + + +struct mwServiceResolve { +  struct mwService service; + +  struct mwChannel *channel;  /**< channel for this service */ +  GHashTable *searches;       /**< guint32:struct mw_search */ +  guint32 counter;            /**< incremented to provide searche IDs */ +}; + + +/** structure representing an active search. keeps track of the ID, +    the handler, and the optional user data and cleanup */ +struct mw_search { +  struct mwServiceResolve *service; +  guint32 id; +  mwResolveHandler handler; +  gpointer data; +  GDestroyNotify cleanup; +}; + + +static struct mw_search *search_new(struct mwServiceResolve *srvc, +				    mwResolveHandler handler, +				    gpointer data, GDestroyNotify cleanup) { + +  struct mw_search *search = g_new0(struct mw_search, 1); + +  search->service = srvc; +  search->handler = handler; + +  /* we want search IDs that aren't SEARCH_ERROR */ +  do { +    search->id = srvc->counter++; +  } while(search->id == SEARCH_ERROR); + +  search->data = data; +  search->cleanup = cleanup; + +  return search; +} + + +/** called whenever a mw_search is removed from the searches table of +    the service */ +static void search_free(struct mw_search *search) { +  g_return_if_fail(search != NULL); + +  if(search->cleanup) +    search->cleanup(search->data); +   +  g_free(search); +} + + +static const char *get_name(struct mwService *srvc) { +  return "Identity Resolution"; +} + + +static const char *get_desc(struct mwService *srvc) { +  return "Resolves short IDs to full IDs"; +} + + +static struct mwChannel *make_channel(struct mwServiceResolve *srvc) { +  struct mwSession *session; +  struct mwChannelSet *cs; +  struct mwChannel *chan; + +  session = mwService_getSession(MW_SERVICE(srvc)); +  cs = mwSession_getChannels(session); +  chan = mwChannel_newOutgoing(cs); +  +  mwChannel_setService(chan, MW_SERVICE(srvc)); +  mwChannel_setProtoType(chan, PROTOCOL_TYPE); +  mwChannel_setProtoVer(chan, PROTOCOL_VER); + +  return mwChannel_create(chan)? NULL: chan; +} + + +static void start(struct mwServiceResolve *srvc) { +  struct mwChannel *chan; + +  g_return_if_fail(srvc != NULL); + +  chan = make_channel(srvc); +  if(chan) { +    srvc->channel = chan; +  } else { +    mwService_stopped(MW_SERVICE(srvc)); +    return; +  } + +  /* semi-lazily create the searches table */ +  srvc->searches = g_hash_table_new_full(g_direct_hash, g_direct_equal, +					 NULL, (GDestroyNotify) search_free); +} + + +static void stop(struct mwServiceResolve *srvc) { +  g_return_if_fail(srvc != NULL); + +  if(srvc->channel) { +    mwChannel_destroy(srvc->channel, ERR_SUCCESS, NULL); +    srvc->channel = NULL; +  } + +  /* destroy all the pending requests. */ +  g_hash_table_destroy(srvc->searches); +  srvc->searches = NULL; +   +  mwService_stopped(MW_SERVICE(srvc)); +} + + +static void clear(struct mwServiceResolve *srvc) { +  if(srvc->searches) { +    g_hash_table_destroy(srvc->searches); +    srvc->searches = NULL; +  } +} + + +static void recv_create(struct mwServiceResolve *srvc, +			struct mwChannel *chan, +			struct mwMsgChannelCreate *msg) { + +  /* you serve me, not the other way around */ +  mwChannel_destroy(chan, ERR_FAILURE, NULL); +} + + +static void recv_accept(struct mwServiceResolve *srvc, +			struct mwChannel *chan, +			struct mwMsgChannelAccept *msg) { +   +  g_return_if_fail(srvc != NULL); +  g_return_if_fail(chan != NULL); +  g_return_if_fail(chan == srvc->channel); + +  mwService_started(MW_SERVICE(srvc)); +} + + +static void recv_destroy(struct mwServiceResolve *srvc, +			 struct mwChannel *chan, +			 struct mwMsgChannelDestroy *msg) { + +  struct mwSession *session; + +  g_return_if_fail(srvc != NULL); +  g_return_if_fail(chan != NULL); +  g_return_if_fail(chan == srvc->channel); + +  srvc->channel = NULL; +  mwService_stop(MW_SERVICE(srvc)); + +  session = mwService_getSession(MW_SERVICE(srvc)); +  g_return_if_fail(session != NULL); + +  mwSession_senseService(session, mwService_getType(MW_SERVICE(srvc))); +} + + +static GList *load_matches(struct mwGetBuffer *b, guint32 count) { +  GList *matches = NULL; + +  while(count--) { +    struct mwResolveMatch *m = g_new0(struct mwResolveMatch, 1); + +    mwString_get(b, &m->id); +    mwString_get(b, &m->name); +    mwString_get(b, &m->desc); +    guint32_get(b, &m->type); +  +    matches = g_list_append(matches, m); +  } + +  return matches; +} + + +static GList *load_results(struct mwGetBuffer *b, guint32 count) { +  GList *results = NULL; + +  while(count--) { +    struct mwResolveResult *r = g_new0(struct mwResolveResult, 1); +    guint32 junk, matches; + +    guint32_get(b, &junk); +    guint32_get(b, &r->code); +    mwString_get(b, &r->name); + +    guint32_get(b, &matches); +    r->matches = load_matches(b, matches); + +    results = g_list_append(results, r); +  } + +  return results; +} + + +static void free_matches(GList *matches) { +  for(; matches; matches = g_list_delete_link(matches, matches)) { +    struct mwResolveMatch *m = matches->data; +    g_free(m->id); +    g_free(m->name); +    g_free(m->desc); +    g_free(m); +  } +} + + +static void free_results(GList *results) { +  for(; results; results = g_list_delete_link(results, results)) { +    struct mwResolveResult *r = results->data; +    g_free(r->name); +    free_matches(r->matches); +    g_free(r); +  } +} + + +static void recv(struct mwServiceResolve *srvc, +		 struct mwChannel *chan, +		 guint16 type, struct mwOpaque *data) { + +  struct mwGetBuffer *b; +  guint32 junk, id, code, count; +  struct mw_search *search; + +  g_return_if_fail(srvc != NULL); +  g_return_if_fail(chan != NULL); +  g_return_if_fail(chan == srvc->channel); +  g_return_if_fail(data != NULL); + +  if(type != RESOLVE_ACTION) { +    mw_mailme_opaque(data, "unknown message in resolve service: 0x%04x", type); +    return; +  } + +  b = mwGetBuffer_wrap(data); +  guint32_get(b, &junk); +  guint32_get(b, &id); +  guint32_get(b, &code); +  guint32_get(b, &count); + +  if(mwGetBuffer_error(b)) { +    g_warning("error parsing search result"); +    mwGetBuffer_free(b); +    return; +  } +   +  search = g_hash_table_lookup(srvc->searches, GUINT_TO_POINTER(id)); + +  if(search) { +    GList *results = load_results(b, count); +    if(mwGetBuffer_error(b)) { +      g_warning("error parsing search results"); +    } else { +      g_debug("triggering handler"); +      search->handler(srvc, id, code, results, search->data); +    } +    free_results(results); +    g_hash_table_remove(srvc->searches, GUINT_TO_POINTER(id)); + +  } else { +    g_debug("no search found: 0x%x", id); +  } + +  mwGetBuffer_free(b); +} + + +struct mwServiceResolve *mwServiceResolve_new(struct mwSession *session) { +  struct mwServiceResolve *srvc_resolve; +  struct mwService *srvc; + +  g_return_val_if_fail(session != NULL, NULL); + +  srvc_resolve = g_new0(struct mwServiceResolve, 1); + +  srvc = MW_SERVICE(srvc_resolve); + +  mwService_init(srvc, session, mwService_RESOLVE); +  srvc->get_name = get_name; +  srvc->get_desc = get_desc; +  srvc->recv_create = (mwService_funcRecvCreate) recv_create; +  srvc->recv_accept = (mwService_funcRecvAccept) recv_accept; +  srvc->recv_destroy = (mwService_funcRecvDestroy) recv_destroy; +  srvc->recv = (mwService_funcRecv) recv; +  srvc->start = (mwService_funcStart) start; +  srvc->stop = (mwService_funcStop) stop; +  srvc->clear = (mwService_funcClear) clear; + +  return srvc_resolve; +} + + +guint32 mwServiceResolve_resolve(struct mwServiceResolve *srvc, +				 GList *queries, enum mwResolveFlag flags, +				 mwResolveHandler handler, +				 gpointer data, GDestroyNotify cleanup) { + +  struct mw_search *search; +  struct mwPutBuffer *b; +  struct mwOpaque o = { 0, 0 }; +  int ret, count = 0; + +  g_return_val_if_fail(srvc != NULL, SEARCH_ERROR); +  g_return_val_if_fail(handler != NULL, SEARCH_ERROR); + +  count = g_list_length(queries); +  g_return_val_if_fail(count > 0, SEARCH_ERROR); + +  search = search_new(srvc, handler, data, cleanup); + +  b = mwPutBuffer_new(); +  guint32_put(b, 0x00); /* to be overwritten */ +  guint32_put(b, search->id); +  guint32_put(b, count); +  for(; queries; queries = queries->next) +    mwString_put(b, queries->data); +  guint32_put(b, flags); + +  mwPutBuffer_finalize(&o, b); +   +  ret = mwChannel_send(srvc->channel, RESOLVE_ACTION, &o); +  if(ret) { +    search_free(search); +    return SEARCH_ERROR; + +  } else { +    g_hash_table_insert(srvc->searches, +			GUINT_TO_POINTER(search->id), search); +    return search->id; +  } +} + + +void mwServiceResolve_cancelResolve(struct mwServiceResolve *srvc, +				    guint32 id) { + +  g_return_if_fail(srvc != NULL); +  g_return_if_fail(srvc->searches != NULL); + +  g_hash_table_remove(srvc->searches, GUINT_TO_POINTER(id)); +} + + +/// Miranda NG adaptation start - new method +struct mwService *mwServiceResolve_getService(struct mwServiceResolve *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return &(srvc->service); +} +/// Miranda NG adaptation end diff --git a/protocols/Sametime/src/meanwhile/src/srvc_store.c b/protocols/Sametime/src/meanwhile/src/srvc_store.c new file mode 100644 index 0000000000..f537195e08 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/srvc_store.c @@ -0,0 +1,615 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <glib/glist.h> + +#include "mw_channel.h" +#include "mw_debug.h" +#include "mw_error.h" +#include "mw_message.h" +#include "mw_service.h" +#include "mw_session.h" +#include "mw_srvc_store.h" + + +#define PROTOCOL_TYPE  0x00000025 +#define PROTOCOL_VER   0x00000001 + + +enum storage_action { +  action_load    = 0x0004, +  action_loaded  = 0x0005, +  action_save    = 0x0006, +  action_saved   = 0x0007, +}; + + +struct mwStorageUnit { +  /** key by which data is referenced in service +      @see mwStorageKey */ +  guint32 key; + +  /** Data associated with key in service */ +  struct mwOpaque data; +}; + + +struct mwStorageReq { +  guint32 id;                  /**< unique id for this request */ +  guint32 result_code;         /**< result code for completed request */ +  enum storage_action action;  /**< load or save */ +  struct mwStorageUnit *item;  /**< the key/data pair */  +  mwStorageCallback cb;        /**< callback to notify upon completion */ +  gpointer data;               /**< user data to pass with callback */ +  GDestroyNotify data_free;    /**< optionally frees user data */ +}; + + +struct mwServiceStorage { +  struct mwService service; + +  /** collection of mwStorageReq */ +  GList *pending; + +  /** current service channel */ +  struct mwChannel *channel; + +  /** keep track of the counter */ +  guint32 id_counter; +}; + + +static void request_get(struct mwGetBuffer *b, struct mwStorageReq *req) { +  guint32 id, count, junk; + +  if(mwGetBuffer_error(b)) return; + +  guint32_get(b, &id); +  guint32_get(b, &req->result_code); + +  if(req->action == action_loaded) { +    guint32_get(b, &count); + +    if(count > 0) { +      guint32_get(b, &junk); +      guint32_get(b, &req->item->key); + +      mwOpaque_clear(&req->item->data); +      mwOpaque_get(b, &req->item->data); +    } +  } +} + + +static void request_put(struct mwPutBuffer *b, struct mwStorageReq *req) { + +  guint32_put(b, req->id); +  guint32_put(b, 1); + +  if(req->action == action_save) { +    guint32_put(b, 20 + req->item->data.len); /* ugh, offset garbage */ +    guint32_put(b, req->item->key); +    mwOpaque_put(b, &req->item->data); + +  } else { +    guint32_put(b, req->item->key); +  } +} + + +static int request_send(struct mwChannel *chan, struct mwStorageReq *req) { +  struct mwPutBuffer *b; +  struct mwOpaque o = { 0, 0 }; +  int ret; + +  b = mwPutBuffer_new(); +  request_put(b, req); + +  mwPutBuffer_finalize(&o, b); +  ret = mwChannel_send(chan, req->action, &o); +  mwOpaque_clear(&o); + +  if(! ret) { +    if(req->action == action_save) { +      req->action = action_saved; +    } else if(req->action == action_load) { +      req->action = action_loaded; +    } +  } + +  return ret; +} + + +static struct mwStorageReq *request_find(struct mwServiceStorage *srvc, +					 guint32 id) { +  GList *l; + +  for(l = srvc->pending; l; l = l->next) { +    struct mwStorageReq *r = l->data; +    if(r->id == id) return r; +  } + +  return NULL; +} + + +static const char *action_str(enum storage_action act) { +  switch(act) { +  case action_load:    return "load"; +  case action_loaded:  return "loaded"; +  case action_save:    return "save"; +  case action_saved:   return "saved"; +  default:             return "UNKNOWN"; +  } +} + + +static void request_trigger(struct mwServiceStorage *srvc, +			    struct mwStorageReq *req) { + +  struct mwStorageUnit *item = req->item; + +  g_message("storage request %s: key = 0x%x, result = 0x%x, length = %u", +	    action_str(req->action), +	    item->key, req->result_code, (guint) item->data.len); +   +  if(req->cb) +    req->cb(srvc, req->result_code, item, req->data); +} + + +static void request_free(struct mwStorageReq *req) { +  if(req->data_free) { +    req->data_free(req->data); +    req->data = NULL; +    req->data_free = NULL; +  } + +  mwStorageUnit_free(req->item); +  g_free(req); +} + + +static void request_remove(struct mwServiceStorage *srvc, +			   struct mwStorageReq *req) { + +  srvc->pending = g_list_remove_all(srvc->pending, req); +  request_free(req); +} + + +static const char *get_name(struct mwService *srvc) { +  return "User Storage"; +} + + +static const char *get_desc(struct mwService *srvc) { +  return "Stores user data and settings on the server"; +} + + +static struct mwChannel *make_channel(struct mwServiceStorage *srvc) { +  struct mwSession *session; +  struct mwChannelSet *cs; +  struct mwChannel *chan; + +  session = mwService_getSession(MW_SERVICE(srvc)); +  cs = mwSession_getChannels(session); +  chan = mwChannel_newOutgoing(cs); +  +  mwChannel_setService(chan, MW_SERVICE(srvc)); +  mwChannel_setProtoType(chan, PROTOCOL_TYPE); +  mwChannel_setProtoVer(chan, PROTOCOL_VER); + +  return mwChannel_create(chan)? NULL: chan; +} + + +static void start(struct mwService *srvc) { +  struct mwServiceStorage *srvc_store; +  struct mwChannel *chan; + +  g_return_if_fail(srvc != NULL); +  srvc_store = (struct mwServiceStorage *) srvc; + +  chan = make_channel(srvc_store); +  if(chan) { +    srvc_store->channel = chan; +  } else { +    mwService_stopped(srvc); +  } +} + + +static void stop(struct mwService *srvc) { + +  struct mwServiceStorage *srvc_store; +  GList *l; + +  g_return_if_fail(srvc != NULL); +  srvc_store = (struct mwServiceStorage *) srvc; + +  if(srvc_store->channel) { +    mwChannel_destroy(srvc_store->channel, ERR_SUCCESS, NULL); +    srvc_store->channel = NULL; +  } + +#if 1 +  /* the new way */ +  /* remove pending requests. Sometimes we can crash the storage +     service, and when that happens, we end up resending the killer +     request over and over again, and the service never stays up */ +  for(l = srvc_store->pending; l; l = l->next) +    request_free(l->data); + +  g_list_free(srvc_store->pending); +  srvc_store->pending = NULL; + +  srvc_store->id_counter = 0; + +#else +  /* the old way */ +  /* reset all of the started requests to their unstarted states */ +  for(l = srvc_store->pending; l; l = l->next) { +    struct mwStorageReq *req = l->data; + +    if(req->action == action_loaded) { +      req->action = action_load; +    } else if(req->action == action_saved) { +      req->action = action_save; +    } +  } +#endif + +  mwService_stopped(srvc); +} + + +static void recv_channelAccept(struct mwService *srvc, +			       struct mwChannel *chan, +			       struct mwMsgChannelAccept *msg) { +  +  struct mwServiceStorage *srvc_stor; +  GList *l; + +  g_return_if_fail(srvc != NULL); +  srvc_stor = (struct mwServiceStorage *) srvc; + +  g_return_if_fail(chan != NULL); +  g_return_if_fail(chan == srvc_stor->channel); + +  /* send all pending requests */ +  for(l = srvc_stor->pending; l; l = l->next) { +    struct mwStorageReq *req = l->data; + +    if(req->action == action_save || req->action == action_load) { +      request_send(chan, req); +    } +  } + +  mwService_started(srvc); +} + + +static void recv_channelDestroy(struct mwService *srvc, +				struct mwChannel *chan, +				struct mwMsgChannelDestroy *msg) { + +  struct mwSession *session; +  struct mwServiceStorage *srvc_stor; + +  g_return_if_fail(srvc != NULL); +  g_return_if_fail(chan != NULL); + +  session = mwService_getSession(srvc); +  g_return_if_fail(session != NULL); + +  srvc_stor = (struct mwServiceStorage *) srvc; +  srvc_stor->channel = NULL; + +  mwService_stop(srvc); +  mwSession_senseService(session, mwService_getType(srvc)); +} + + +static void recv(struct mwService *srvc, struct mwChannel *chan, +		 guint16 type, struct mwOpaque *data) { + +  /* process into results, trigger callbacks */ + +  struct mwGetBuffer *b; +  struct mwServiceStorage *srvc_stor; +  struct mwStorageReq *req; +  guint32 id; + +  g_return_if_fail(srvc != NULL); +  srvc_stor = (struct mwServiceStorage *) srvc; + +  g_return_if_fail(chan != NULL); +  g_return_if_fail(chan == srvc_stor->channel); +  g_return_if_fail(data != NULL); + +  b = mwGetBuffer_wrap(data); + +  id = guint32_peek(b); +  req = request_find(srvc_stor, id); + +  if(! req) { +    g_warning("couldn't find request 0x%x in storage service", id); +    mwGetBuffer_free(b); +    return; +  } + +  g_return_if_fail(req->action == type); +  request_get(b, req); + +  if(mwGetBuffer_error(b)) { +    mw_mailme_opaque(data, "storage request 0x%x, type: 0x%x", id, type); + +  } else { +    request_trigger(srvc_stor, req); +  } + +  mwGetBuffer_free(b); +  request_remove(srvc_stor, req); +} + + +static void clear(struct mwService *srvc) { +  struct mwServiceStorage *srvc_stor; +  GList *l; + +  srvc_stor = (struct mwServiceStorage *) srvc; + +  for(l = srvc_stor->pending; l; l = l->next) +    request_free(l->data); + +  g_list_free(srvc_stor->pending); +  srvc_stor->pending = NULL; + +  srvc_stor->id_counter = 0; +} + + +struct mwServiceStorage *mwServiceStorage_new(struct mwSession *session) { +  struct mwServiceStorage *srvc_store; +  struct mwService *srvc; + +  srvc_store = g_new0(struct mwServiceStorage, 1); +  srvc = MW_SERVICE(srvc_store); + +  mwService_init(srvc, session, mwService_STORAGE); +  srvc->get_name = get_name; +  srvc->get_desc = get_desc; +  srvc->recv_accept = recv_channelAccept; +  srvc->recv_destroy = recv_channelDestroy; +  srvc->recv = recv; +  srvc->start = start; +  srvc->stop = stop; +  srvc->clear = clear; + +  return srvc_store; +} + + +struct mwStorageUnit *mwStorageUnit_new(guint32 key) { +  struct mwStorageUnit *u; + +  u = g_new0(struct mwStorageUnit, 1); +  u->key = key; + +  return u; +} + + +struct mwStorageUnit *mwStorageUnit_newOpaque(guint32 key, +					      struct mwOpaque *data) { +  struct mwStorageUnit *u; + +  u = g_new0(struct mwStorageUnit, 1); +  u->key = key; + +  if(data) +    mwOpaque_clone(&u->data, data); + +  return u; +} + + +struct mwStorageUnit *mwStorageUnit_newBoolean(guint32 key, +					       gboolean val) { + +  return mwStorageUnit_newInteger(key, (guint32) val); +} + + +struct mwStorageUnit *mwStorageUnit_newInteger(guint32 key, +					       guint32 val) { +  struct mwStorageUnit *u; +  struct mwPutBuffer *b; + +  u = g_new0(struct mwStorageUnit, 1); +  u->key = key; +   +  b = mwPutBuffer_new(); +  guint32_put(b, val); +  mwPutBuffer_finalize(&u->data, b); + +  return u; +} + + +struct mwStorageUnit *mwStorageUnit_newString(guint32 key, +					      const char *str) { +  struct mwStorageUnit *u; +  struct mwPutBuffer *b; + +  u = g_new0(struct mwStorageUnit, 1); +  u->key = key; + +  b = mwPutBuffer_new(); +  mwString_put(b, str); +  mwPutBuffer_finalize(&u->data, b); + +  return u; +} + + +guint32 mwStorageUnit_getKey(struct mwStorageUnit *item) { +  g_return_val_if_fail(item != NULL, 0x00); /* feh, unsafe */ +  return item->key; +} + + +gboolean mwStorageUnit_asBoolean(struct mwStorageUnit *item, +				 gboolean val) { + +  return !! mwStorageUnit_asInteger(item, (guint32) val); +} + + +guint32 mwStorageUnit_asInteger(struct mwStorageUnit *item, +				guint32 val) { +  struct mwGetBuffer *b; +  guint32 v; + +  g_return_val_if_fail(item != NULL, val); + +  b = mwGetBuffer_wrap(&item->data); + +  guint32_get(b, &v); +  if(! mwGetBuffer_error(b)) val = v; +  mwGetBuffer_free(b); + +  return val; +} + + +char *mwStorageUnit_asString(struct mwStorageUnit *item) { +  struct mwGetBuffer *b; +  char *c = NULL; + +  g_return_val_if_fail(item != NULL, NULL); + +  b = mwGetBuffer_wrap(&item->data); + +  mwString_get(b, &c); + +  if(mwGetBuffer_error(b)) +    g_debug("error obtaining string value from opaque"); + +  mwGetBuffer_free(b); + +  return c; +} + + +struct mwOpaque *mwStorageUnit_asOpaque(struct mwStorageUnit *item) { +  g_return_val_if_fail(item != NULL, NULL); +  return &item->data; +} + + +void mwStorageUnit_free(struct mwStorageUnit *item) { +  if(! item) return; + +  mwOpaque_clear(&item->data); +  g_free(item); +} + + +static struct mwStorageReq *request_new(struct mwServiceStorage *srvc, +					struct mwStorageUnit *item, +					mwStorageCallback cb, +					gpointer data, GDestroyNotify df) { + +  struct mwStorageReq *req = g_new0(struct mwStorageReq, 1); + +  req->id = ++srvc->id_counter; +  req->item = item; +  req->cb = cb; +  req->data = data; +  req->data_free = df; + +  return req; +} + + +void mwServiceStorage_load(struct mwServiceStorage *srvc, +			   struct mwStorageUnit *item, +			   mwStorageCallback cb, +			   gpointer data, GDestroyNotify d_free) { + +  /* - construct a request +     - put request at end of pending +     - if channel is open and connected +       - compose the load message +       - send message +       - set request to sent +     - else +       - start service +  */  + +  struct mwStorageReq *req; + +  req = request_new(srvc, item, cb, data, d_free); +  req->action = action_load; + +  srvc->pending = g_list_append(srvc->pending, req); + +  if(MW_SERVICE_IS_STARTED(MW_SERVICE(srvc))) +    request_send(srvc->channel, req); +} + + +void mwServiceStorage_save(struct mwServiceStorage *srvc, +			   struct mwStorageUnit *item, +			   mwStorageCallback cb, +			   gpointer data, GDestroyNotify d_free) { + +  /* - construct a request +     - put request at end of pending +     - if channel is open and connected +       - compose the save message +       - send message +       - set request to sent +     - else +       - start service +  */ + +  struct mwStorageReq *req; + +  req = request_new(srvc, item, cb, data, d_free); +  req->action = action_save; + +  srvc->pending = g_list_append(srvc->pending, req); + +  if(MW_SERVICE_IS_STARTED(MW_SERVICE(srvc))) +    request_send(srvc->channel, req); +} + + +/// Miranda NG adaptation start - new method +struct mwService *mwServiceStorage_getService(struct mwServiceStorage *srvc) { +  g_return_val_if_fail(srvc != NULL, NULL); +  return &(srvc->service); +} +/// Miranda NG adaptation end diff --git a/protocols/Sametime/src/meanwhile/src/st_list.c b/protocols/Sametime/src/meanwhile/src/st_list.c new file mode 100644 index 0000000000..949696a4a1 --- /dev/null +++ b/protocols/Sametime/src/meanwhile/src/st_list.c @@ -0,0 +1,668 @@ + +/* +  Meanwhile - Unofficial Lotus Sametime Community Client Library +  Copyright (C) 2004  Christopher (siege) O'Brien +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. +   +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Library General Public License for more details. +   +  You should have received a copy of the GNU Library General Public +  License along with this library; if not, write to the Free +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <stdio.h> +#include <string.h> +#include <glib/gstring.h> + +#include "mw_debug.h" +#include "mw_util.h" +#include "mw_st_list.h" + + +struct mwSametimeList { +  guint ver_major; +  guint ver_minor; +  guint ver_micro; + +  GList *groups; +}; + + +struct mwSametimeGroup { +  struct mwSametimeList *list; + +  enum mwSametimeGroupType type; +  char *name; +  char *alias; +  gboolean open; + +  GList *users; +}; + + +struct mwSametimeUser { +  struct mwSametimeGroup *group; + +  enum mwSametimeUserType type; +  struct mwIdBlock id; +  char *name; +  char *alias; +}; + + +static void user_free(struct mwSametimeUser *u) { +  struct mwSametimeGroup *g; + +  g = u->group; +  g->users = g_list_remove(g->users, u); + +  mwIdBlock_clear(&u->id); +  g_free(u->name); +  g_free(u->alias); +  g_free(u); +} + + +static void group_free(struct mwSametimeGroup *g) { +  struct mwSametimeList *l; + +  l = g->list; +  l->groups = g_list_remove(l->groups, g); + +  while(g->users) +    mwSametimeUser_free(g->users->data); + +  g_free(g->name); +  g_free(g->alias); +  g_free(g); +} + + +static void list_free(struct mwSametimeList *l) { +  while(l->groups) +    mwSametimeGroup_free(l->groups->data); + +  g_free(l); +} + + +struct mwSametimeList * +mwSametimeList_new() { + +  struct mwSametimeList *stl; + +  stl = g_new0(struct mwSametimeList, 1); +  stl->ver_major = ST_LIST_MAJOR; +  stl->ver_minor = ST_LIST_MINOR; +  stl->ver_micro = ST_LIST_MICRO; + +  return stl; +} + + +void mwSametimeList_setMajor(struct mwSametimeList *l, guint v) { +  g_return_if_fail(l != NULL); +  l->ver_major = v; +} + + +guint mwSametimeList_getMajor(struct mwSametimeList *l) { +  g_return_val_if_fail(l != NULL, 0); +  return l->ver_major; +} + + +void mwSametimeList_setMinor(struct mwSametimeList *l, guint v) { +  g_return_if_fail(l != NULL); +  l->ver_minor = v; +} + + +guint mwSametimeList_getMinor(struct mwSametimeList *l) { +  g_return_val_if_fail(l != NULL, 0); +  return l->ver_minor; +} + + +void mwSametimeList_setMicro(struct mwSametimeList *l, guint v) { +  g_return_if_fail(l != NULL); +  l->ver_micro = v; +} + + +guint mwSametimeList_getMicro(struct mwSametimeList *l) { +  g_return_val_if_fail(l != NULL, 0); +  return l->ver_micro; +} + + +GList *mwSametimeList_getGroups(struct mwSametimeList *l) { +  g_return_val_if_fail(l != NULL, NULL); +  return g_list_copy(l->groups); +} + + +struct mwSametimeGroup * +mwSametimeList_findGroup(struct mwSametimeList *l, +			 const char *name) { +  GList *s; + +  g_return_val_if_fail(l != NULL, NULL); +  g_return_val_if_fail(name != NULL, NULL); +  g_return_val_if_fail(*name != '\0', NULL); + +  for(s = l->groups; s; s = s->next) { +    struct mwSametimeGroup *g = s->data; +    if(! strcmp(g->name, name)) return g; +  } + +  return NULL; +} + + +void mwSametimeList_free(struct mwSametimeList *l) { +  g_return_if_fail(l != NULL); +  list_free(l); +} + + +struct mwSametimeGroup * +mwSametimeGroup_new(struct mwSametimeList *list, +		    enum mwSametimeGroupType type, +		    const char *name) { +   +  struct mwSametimeGroup *stg; + +  g_return_val_if_fail(list != NULL, NULL); +  g_return_val_if_fail(name != NULL, NULL); +  g_return_val_if_fail(*name != '\0', NULL); + +  stg = g_new0(struct mwSametimeGroup, 1); +  stg->list = list; +  stg->type = type; +  stg->name = g_strdup(name); + +  list->groups = g_list_append(list->groups, stg); + +  return stg; +} + + +enum mwSametimeGroupType mwSametimeGroup_getType(struct mwSametimeGroup *g) { +  g_return_val_if_fail(g != NULL, mwSametimeGroup_UNKNOWN); +  return g->type; +} + + +const char *mwSametimeGroup_getName(struct mwSametimeGroup *g) { +  g_return_val_if_fail(g != NULL, NULL); +  return g->name; +} + + +void mwSametimeGroup_setAlias(struct mwSametimeGroup *g, +			      const char *alias) { +  g_return_if_fail(g != NULL); + +  g_free(g->alias); +  g->alias = g_strdup(alias); +} + + +const char *mwSametimeGroup_getAlias(struct mwSametimeGroup *g) { +  g_return_val_if_fail(g != NULL, NULL); +  return g->alias; +} + + +void mwSametimeGroup_setOpen(struct mwSametimeGroup *g, gboolean open) { +  g_return_if_fail(g != NULL); +  g->open = open; +} + + +gboolean mwSametimeGroup_isOpen(struct mwSametimeGroup *g) { +  g_return_val_if_fail(g != NULL, FALSE); +  return g->open; +} + + +struct mwSametimeList *mwSametimeGroup_getList(struct mwSametimeGroup *g) { +  g_return_val_if_fail(g != NULL, NULL); +  return g->list; +} + + +GList *mwSametimeGroup_getUsers(struct mwSametimeGroup *g) { +  g_return_val_if_fail(g != NULL, NULL); +  return g_list_copy(g->users); +} + + +struct mwSametimeUser * +mwSametimeGroup_findUser(struct mwSametimeGroup *g, +			 struct mwIdBlock *user) { +  GList *s; + +  g_return_val_if_fail(g != NULL, NULL); +  g_return_val_if_fail(user != NULL, NULL); + +  for(s = g->users; s; s = s->next) { +    struct mwSametimeUser *u = s->data; +    if(mwIdBlock_equal(user, &u->id)) return u; +  } + +  return NULL; +} + + +void mwSametimeGroup_free(struct mwSametimeGroup *g) { +  g_return_if_fail(g != NULL); +  g_return_if_fail(g->list != NULL); +  group_free(g); +} + + +struct mwSametimeUser * +mwSametimeUser_new(struct mwSametimeGroup *group, +		   enum mwSametimeUserType type, +		   struct mwIdBlock *id) { + +  struct mwSametimeUser *stu; + +  g_return_val_if_fail(group != NULL, NULL); +  g_return_val_if_fail(id != NULL, NULL); +   +  stu = g_new0(struct mwSametimeUser, 1); +  stu->group = group; +  stu->type = type; +  mwIdBlock_clone(&stu->id, id); + +  group->users = g_list_append(group->users, stu); +   +  return stu; +} + + +struct mwSametimeGroup *mwSametimeUser_getGroup(struct mwSametimeUser *u) { +  g_return_val_if_fail(u != NULL, NULL); +  return u->group; +} + + +enum mwSametimeUserType mwSametimeUser_getType(struct mwSametimeUser *u) { +  g_return_val_if_fail(u != NULL, mwSametimeUser_UNKNOWN); +  return u->type; +} + + +const char *mwSametimeUser_getUser(struct mwSametimeUser *u) { +  g_return_val_if_fail(u != NULL, NULL); +  return u->id.user; +} + + +const char *mwSametimeUser_getCommunity(struct mwSametimeUser *u) { +  g_return_val_if_fail(u != NULL, NULL); +  return u->id.community; +} + + +void mwSametimeUser_setShortName(struct mwSametimeUser *u, const char *name) { +  g_return_if_fail(u != NULL); +  g_free(u->name); +  u->name = g_strdup(name); +} + + +const char *mwSametimeUser_getShortName(struct mwSametimeUser *u) { +  g_return_val_if_fail(u != NULL, NULL); +  return u->name; +} + + +void mwSametimeUser_setAlias(struct mwSametimeUser *u, const char *alias) { +  g_return_if_fail(u != NULL); +  g_free(u->alias); +  u->alias = g_strdup(alias); +} + + +const char *mwSametimeUser_getAlias(struct mwSametimeUser *u) { +  g_return_val_if_fail(u != NULL, NULL); +  return u->alias; +} + + +void mwSametimeUser_free(struct mwSametimeUser *u) { +  g_return_if_fail(u != NULL); +  g_return_if_fail(u->group != NULL); +  user_free(u); +} + + +static void str_replace(char *str, char from, char to) { +  if(! str) return; +  for(; *str; str++) if(*str == from) *str = to; +} + + +static char user_type_to_char(enum mwSametimeUserType type) { +  switch(type) { +  case mwSametimeUser_NORMAL:    return '1'; +  case mwSametimeUser_EXTERNAL:  return '2'; +  case mwSametimeUser_UNKNOWN: +  default:                       return '9'; +  } +} + + +static enum mwSametimeUserType user_char_to_type(char type) { +  switch(type) { +  case '1':  return mwSametimeUser_NORMAL; +  case '2':  return mwSametimeUser_EXTERNAL; +  default:   return mwSametimeUser_UNKNOWN; +  } +} + + +static void user_put(GString *str, struct mwSametimeUser *u) { +  char *id, *name, *alias; +  char type; +   +  id = g_strdup(u->id.user); +  name = g_strdup(u->name); +  alias = g_strdup(u->alias); +  type = user_type_to_char(u->type); + +  if(id) str_replace(id, ' ', ';'); +  if(name) str_replace(name, ' ', ';'); +  if(alias) str_replace(alias, ' ', ';'); + +  if(!name && alias) { +    name = alias; +    alias = NULL; +  } + +  g_string_append_printf(str, "U %s%c:: %s,%s\r\n", +			 id, type, (name? name: ""), (alias? alias: "")); + +  g_free(id); +  g_free(name); +  g_free(alias);   +} + + +static char group_type_to_char(enum mwSametimeGroupType type) { +  switch(type) { +  case mwSametimeGroup_NORMAL:   return '2'; +  case mwSametimeGroup_DYNAMIC:  return '3'; +  case mwSametimeGroup_UNKNOWN: +  default:                       return '9'; +  } +} + + +static enum mwSametimeGroupType group_char_to_type(char type) { +  switch(type) { +  case '2':  return mwSametimeGroup_NORMAL; +  case '3':  return mwSametimeGroup_DYNAMIC; +  default:   return mwSametimeGroup_UNKNOWN; +  } +} + + +static void group_put(GString *str, struct mwSametimeGroup *g) { +  char *name, *alias; +  char type; +  GList *gl; + +  name = g_strdup(g->name); +  alias = g_strdup((g->alias)? g->alias: name); +  type = group_type_to_char(g->type); + +  str_replace(name, ' ', ';'); +  str_replace(alias, ' ', ';'); + +  g_string_append_printf(str, "G %s%c %s %c\r\n", +			 name, type, alias, (g->open? 'O':'C')); + +  for(gl = g->users; gl; gl = gl->next) { +    user_put(str, gl->data); +  } + +  g_free(name); +  g_free(alias); +} + + +/** composes a GString with the written contents of a sametime list */ +static GString *list_store(struct mwSametimeList *l) { +  GString *str; +  GList *gl; + +  g_return_val_if_fail(l != NULL, NULL); + +  str = g_string_new(NULL); +  g_string_append_printf(str, "Version=%u.%u.%u\r\n", +			 l->ver_major, l->ver_minor, l->ver_micro); + +  for(gl = l->groups; gl; gl = gl->next) { +    group_put(str, gl->data); +  } + +  return str; +} + + +char *mwSametimeList_store(struct mwSametimeList *l) { +  GString *str; +  char *s; + +  g_return_val_if_fail(l != NULL, NULL); + +  str = list_store(l); +  s = str->str; +  g_string_free(str, FALSE); +  return s; +} + + +void mwSametimeList_put(struct mwPutBuffer *b, struct mwSametimeList *l) { +  GString *str; +  guint16 len; + +  g_return_if_fail(l != NULL); +  g_return_if_fail(b != NULL); + +  str = list_store(l); +  len = (guint16) str->len; +  guint16_put(b, len); +  mwPutBuffer_write(b, str->str, len); + +  g_string_free(str, TRUE); +} + + +static void get_version(const char *line, struct mwSametimeList *l) { +  guint major = 0, minor = 0, micro = 0; +  int ret; + +  ret = sscanf(line, "Version=%u.%u.%u\n", &major, &minor, µ); +  if(ret != 3) { +    g_warning("strange sametime list version line:\n%s", line); +  } + +  l->ver_major = major; +  l->ver_minor = minor; +  l->ver_micro = micro; +} + + +static struct mwSametimeGroup *get_group(const char *line, +					 struct mwSametimeList *l) { +  struct mwSametimeGroup *group; +  char *name, *alias; +  char type = '2', open = 'O'; +  int ret; + +  ret = strlen(line); +  name = g_malloc0(ret); +  alias = g_malloc0(ret); + +  ret = sscanf(line, "G %s %s %c\n", +	       name, alias, &open); + +  if(ret < 3) { +    g_warning("strange sametime list group line:\n%s", line); +  } +   +  str_replace(name, ';', ' '); +  str_replace(alias, ';', ' '); + +  if(name && *name) { +    int l = strlen(name)-1; +    type = name[l]; +    name[l] = '\0'; +  } + +  group = g_new0(struct mwSametimeGroup, 1); +  group->list = l; +  group->name = name; +  group->type = group_char_to_type(type); +  group->alias = alias; +  group->open = (open == 'O'); + +  l->groups = g_list_append(l->groups, group); + +  return group; +} + + +static void get_user(const char *line, struct mwSametimeGroup *g) { +  struct mwSametimeUser *user; +  struct mwIdBlock idb = { 0, 0 }; +  char *name, *alias = NULL; +  char type = '1'; +  int ret; +   +  ret = strlen(line); +  idb.user = g_malloc0(ret); +  name = g_malloc0(ret); + +  ret = sscanf(line, "U %s %s", +	       idb.user, name); + +  if(ret < 2) { +    g_warning("strange sametime list user line:\n%s", line); +  } + +  str_replace(idb.user, ';', ' '); +  str_replace(name, ';', ' '); + +  if(idb.user && *idb.user) { +    char *tmp = strstr(idb.user, "::"); +    if(tmp--) { +      type = *(tmp); +      *tmp = '\0'; +    } +  } + +  if(name && *name) { +    char *tmp = strrchr(name, ','); +    if(tmp) { +      *tmp++ = '\0'; +      if(*tmp) alias = tmp; +    } +  } + +  user = g_new0(struct mwSametimeUser, 1); +  user->group = g; +  user->id.user = idb.user; +  user->type = user_char_to_type(type); +  user->name = name; +  user->alias = g_strdup(alias); +   +  g->users = g_list_append(g->users, user); +} + + +/** returns a line from str, and advances str */ +static char *fetch_line(char **str) { +  char *start = *str; +  char *end; + +  /* move to first non-whitespace character */ +  while(*start && g_ascii_isspace(*start)) start++; +  if(! *start) return NULL; + +  for(end = start + 1; *end; end++) { +    if(*end == '\n' || *end == '\r') { +      *(end++) = '\0'; +      break; +    } +  } + +  *str = end; +  return start; +} + + +static void list_get(const char *lines, struct mwSametimeList *l) { +  char *s = (char *) lines; +  char *line; + +  struct mwSametimeGroup *g = NULL; +   +  while( (line = fetch_line(&s)) ) { +    switch(*line) { +    case 'V': +      get_version(line, l); +      break; + +    case 'G': +      g = get_group(line, l); +      break; + +    case 'U': +      get_user(line, g); +      break; + +    default: +      g_warning("unknown sametime list data line:\n%s", line); +    } +  }   +} + + +struct mwSametimeList *mwSametimeList_load(const char *data) { +  struct mwSametimeList *l; + +  g_return_val_if_fail(data != NULL, NULL); +   +  l = mwSametimeList_new(); +  list_get(data, l); + +  return l; +} + + +void mwSametimeList_get(struct mwGetBuffer *b, struct mwSametimeList *l) { +  char *str = NULL; + +  g_return_if_fail(l != NULL); +  g_return_if_fail(b != NULL); + +  mwString_get(b, &str); +  list_get(str, l); +  g_free(str); +} + diff --git a/protocols/Sametime/src/messaging.cpp b/protocols/Sametime/src/messaging.cpp new file mode 100644 index 0000000000..58cc83b600 --- /dev/null +++ b/protocols/Sametime/src/messaging.cpp @@ -0,0 +1,222 @@ +#include "StdAfx.h"
 +#include "sametime.h"
 +
 +
 +CSametimeProto* getProtoFromMwConversation(mwConversation* conv)
 +{
 +	mwServiceIm* serviceIM = mwConversation_getService(conv);
 +	mwService* service = mwServiceIm_getService(serviceIM);
 +	mwSession* session = mwService_getSession(service);
 +	return (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +}
 +
 +
 +void mwIm_conversation_opened(mwConversation* conv)
 +{
 +	CSametimeProto* proto = getProtoFromMwConversation(conv);
 +	proto->debugLog(_T("mwIm_conversation_opened() start"));
 +
 +	mwIdBlock* idb = mwConversation_getTarget(conv);
 +	MCONTACT hContact = proto->FindContactByUserId(idb->user);
 +
 +	if (!hContact) {
 +		proto->debugLog(_T("mwIm_conversation_opened() !hContact"));
 +		mwSametimeList* user_list = mwSametimeList_new();
 +		mwSametimeGroup* stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_NORMAL, Translate("None"));
 +		mwSametimeUser* stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, idb);
 +
 +		proto->AddContact(stuser, (proto->options.add_contacts ? false : true));
 +		proto->GetMoreDetails(idb->user);
 +	}
 +	
 +	ContactMessageQueue::iterator i;
 +	EnterCriticalSection(&proto->q_cs);
 +	if ((i = proto->contact_message_queue.find(hContact)) != proto->contact_message_queue.end()) {
 +		while(i->second.size()) {
 +			mwConversation_send(conv, mwImSend_PLAIN, (gconstpointer)i->second.front().c_str());
 +			i->second.pop();
 +		}
 +		proto->contact_message_queue.erase(i);
 +	}
 +	LeaveCriticalSection(&proto->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)
 +{
 +	CSametimeProto* proto = getProtoFromMwConversation(conv);
 +	proto->debugLog(_T("mwIm_conversation_closed() start err=[%d]"),err);
 +
 +	if (err & ERR_FAILURE && err != CONNECTION_RESET) {
 +		char* msg = mwError(err);
 +		proto->showPopup(TranslateTS(_A2T(msg)), SAMETIME_POPUP_ERROR);
 +		g_free(msg);
 +		if (err == ERR_NO_COMMON_ENCRYPT && !(proto->options.encrypt_session)) {
 +			proto->showPopup(TranslateT("No common encryption method. Try to enable encryption in protocol options."), SAMETIME_POPUP_INFO);
 +		}
 +	}
 +
 +	mwIdBlock* idb = mwConversation_getTarget(conv);
 +	MCONTACT hContact = proto->FindContactByUserId(idb->user);
 +	if (hContact) {
 +		ContactMessageQueue::iterator i;
 +		EnterCriticalSection(&proto->q_cs);
 +		if ((i = proto->contact_message_queue.find(hContact)) != proto->contact_message_queue.end()) {
 +			proto->contact_message_queue.erase(i);
 +		}
 +		LeaveCriticalSection(&proto->q_cs);
 +	}
 +}
 +
 +/** A message has been received on a conversation */
 +void mwIm_conversation_recv(mwConversation* conv, mwImSendType type, gconstpointer msg)
 +{
 +	CSametimeProto* proto = getProtoFromMwConversation(conv);
 +	proto->debugLog(_T("mwIm_conversation_recv() start"));
 +
 +	mwIdBlock* idb = mwConversation_getTarget(conv);
 +	MCONTACT hContact = proto->FindContactByUserId(idb->user);
 +	proto->debugLog(_T("mwIm_conversation_recv() type=[%d] hContact=[%x]"), type, hContact);
 +
 +	if (type == mwImSend_TYPING) {
 +		CallService(MS_PROTO_CONTACTISTYPING, hContact, (LPARAM)(GPOINTER_TO_UINT(msg) == 0 ? 0 : 2));
 +		return;
 +	}
 +
 +	if (type != mwImSend_PLAIN) return;
 +
 +	PROTORECVEVENT pre = {0};
 +	time_t t = time(NULL);
 +	pre.timestamp = t;
 +	pre.flags = PREF_UTF;
 +	pre.szMessage = (char*)msg;
 +	ProtoChainRecvMsg(hContact, &pre);
 +
 +}
 +
 +
 +void mwIm_place_invite(struct mwConversation* conv, const char* message, const char* title, const char* name)
 +{
 +	CSametimeProto* proto = getProtoFromMwConversation(conv);
 +	proto->debugLog(_T("mwIm_place_invite() start"));
 +
 +	///TODO unimplemented
 +
 +	TCHAR* tszMessage = mir_utf8decodeT(message);
 +
 +	TCHAR msg[512];
 +	mir_sntprintf(msg, SIZEOF(msg), TranslateT("SERVICE UNIMPLEMENTED. %s"), tszMessage);
 +	proto->showPopup(msg, SAMETIME_POPUP_INFO);
 +
 +	mir_free(tszMessage);
 +}
 +
 +
 +mwImHandler mwIm_handler = {
 +	mwIm_conversation_opened,
 +	mwIm_conversation_closed,
 +	mwIm_conversation_recv,
 +	mwIm_place_invite,
 +	NULL
 +};
 +
 +
 +HANDLE CSametimeProto::SendMessageToUser(MCONTACT hContact, char* msg_utf8)
 +{
 +	debugLog(_T("CSametimeProto::SendMessageToUser()  hContact=[%x]"), hContact);
 +
 +	mwAwareIdBlock id_block;
 +	if (GetAwareIdFromContact(hContact, &id_block)) {
 +
 +		mwIdBlock idb;
 +		idb.user = id_block.user;
 +		idb.community = id_block.community;
 +
 +		mwConversation* conv = mwServiceIm_getConversation(service_im, &idb);
 +		if (conv) {
 +			if (!mwConversation_isOpen(conv)) {
 +				debugLog(_T("CSametimeProto::SendMessageToUser()  mwConversation_isOpen"));
 +				EnterCriticalSection(&q_cs);
 +				contact_message_queue[hContact].push(msg_utf8);
 +				LeaveCriticalSection(&q_cs);
 +				mwConversation_open(conv);
 +			} else {
 +				debugLog(_T("CSametimeProto::SendMessageToUser()  !mwConversation_isOpen"));
 +				mwConversation_send(conv, mwImSend_PLAIN, (gconstpointer)msg_utf8);
 +			}
 +
 +			free(id_block.user);
 +			return (HANDLE)conv;
 +		}
 +
 +		free(id_block.user);
 +	}
 +
 +	return 0;
 +}
 +
 +
 +void CSametimeProto::SendTyping(MCONTACT hContact, bool typing)
 +{
 +	debugLog(_T("CSametimeProto::SendTyping() hContact=[%x] type=[%d]"), hContact, typing);
 +	
 +	mwAwareIdBlock id_block;
 +	if (GetAwareIdFromContact(hContact, &id_block)) {
 +		mwIdBlock idb;
 +		idb.user = id_block.user;
 +		idb.community = id_block.community;
 +
 +		mwConversation* conv = mwServiceIm_getConversation(service_im, &idb);
 +		if (conv) {
 +			if (mwConversation_isOpen(conv)){
 +				debugLog(_T("CSametimeProto::SendTyping() send"));
 +				mwConversation_send(conv, mwImSend_TYPING, (gconstpointer)GUINT_TO_POINTER(typing ? 1 : 0));
 +			}
 +		}
 +
 +		free(id_block.user);
 +	}
 +}
 +
 +
 +void CSametimeProto::CloseIm(MCONTACT hContact)
 +{
 +	debugLog(_T("CSametimeProto::CloseIm() hContact=[%x]"), hContact);
 +
 +	mwAwareIdBlock id_block;
 +	if (GetAwareIdFromContact(hContact, &id_block)) {
 +		mwIdBlock idb;
 +		idb.user = id_block.user;
 +		idb.community = id_block.community;
 +
 +		mwConversation* conv = mwServiceIm_getConversation(service_im, &idb);
 +		if (conv) {
 +			if (mwConversation_isOpen(conv)){
 +				debugLog(_T("CSametimeProto::CloseIm() mwConversation_close"));
 +				mwConversation_close(conv, 0);
 +			}
 +		}
 +		free(id_block.user);
 +	}
 +}
 +
 +void CSametimeProto::InitMessaging()
 +{
 +	debugLog(_T("CSametimeProto::InitMessaging()"));
 +	InitializeCriticalSection(&q_cs);
 +	mwSession_addService(session, (mwService*)(service_im = mwServiceIm_new(session, &mwIm_handler)));
 +	mwServiceIm_setClientType(service_im, mwImClient_PLAIN);
 +}
 +
 +void CSametimeProto::DeinitMessaging()
 +{
 +	debugLog(_T("CSametimeProto::DeinitMessaging()"));
 +	mwSession_removeService(session, mwService_IM);
 +	mwService_free((mwService*)service_im);
 +	service_im = 0;
 +	DeleteCriticalSection(&q_cs);
 +}
 +
 diff --git a/protocols/Sametime/src/options.cpp b/protocols/Sametime/src/options.cpp new file mode 100644 index 0000000000..d882233f48 --- /dev/null +++ b/protocols/Sametime/src/options.cpp @@ -0,0 +1,369 @@ +#include "StdAfx.h"
 +#include "sametime.h"
 +
 +
 +#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 INT_PTR CALLBACK DlgProcOptNet(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +
 +	switch ( msg ) {
 +	case WM_INITDIALOG: {
 +
 +		TranslateDialogDefault(hwndDlg);
 +
 +		SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
 +		proto = (CSametimeProto*)lParam;
 +
 +		{
 +			TCHAR verbuf[100];
 +			WORD client_ver = proto->GetClientVersion();
 +			WORD server_ver = proto->GetServerVersion();
 +			if (client_ver)
 +				mir_sntprintf(verbuf, SIZEOF(verbuf), _T("Client proto version: %03d.%03d"), (client_ver & 0xFF00) >> 8, client_ver & 0xFF);
 +			else
 +				mir_sntprintf(verbuf, SIZEOF(verbuf), _T("Disconnected"));
 +			SetDlgItemText(hwndDlg, IDC_ST_CLIENTVER, verbuf);
 +			if (server_ver)
 +				mir_sntprintf(verbuf, SIZEOF(verbuf), _T("Server proto version: %03d.%03d"), (server_ver & 0xFF00) >> 8, server_ver & 0xFF);
 +			else
 +				mir_sntprintf(verbuf, SIZEOF(verbuf), _T("Disconnected"));
 +			SetDlgItemText(hwndDlg, IDC_ST_SERVERVER, verbuf);
 +		}
 +
 +		TCHAR* s;
 +		s = mir_utf8decodeT(proto->options.server_name); SetDlgItemText(hwndDlg, IDC_ED_SNAME, s); mir_free(s);
 +		s = mir_utf8decodeT(proto->options.id); SetDlgItemText(hwndDlg, IDC_ED_NAME, s); mir_free(s);
 +		s = mir_utf8decodeT(proto->options.pword); SetDlgItemText(hwndDlg, IDC_ED_PWORD, s); mir_free(s);
 +
 +		SetDlgItemInt(hwndDlg, IDC_ED_PORT, proto->options.port, FALSE);
 +		CheckDlgButton(hwndDlg, IDC_CHK_GETSERVERCONTACTS, proto->options.get_server_contacts ? TRUE : FALSE);
 +		CheckDlgButton(hwndDlg, IDC_CHK_ADDCONTACTS, proto->options.add_contacts ? TRUE : FALSE);
 +		CheckDlgButton(hwndDlg, IDC_CHK_IDLEAWAY, proto->options.idle_as_away ? TRUE : FALSE);
 +		CheckDlgButton(hwndDlg, IDC_CHK_OLDDEFAULTVER, proto->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] == proto->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, proto->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 (proto->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 (proto->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);
 +					
 +					proto->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);
 +
 +						proto->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) {
 +			TCHAR ws[2048];
 +			char* utf;
 +
 +			GetDlgItemText(hwndDlg, IDC_ED_SNAME, ws, LSTRINGLEN);
 +			strcpy(proto->options.server_name, utf = mir_utf8encodeT(ws)); mir_free(utf);
 +			GetDlgItemText(hwndDlg, IDC_ED_NAME, ws, LSTRINGLEN);
 +			strcpy(proto->options.id, utf = mir_utf8encodeT(ws)); mir_free(utf);
 +			GetDlgItemText(hwndDlg, IDC_ED_PWORD, ws, LSTRINGLEN);
 +			strcpy(proto->options.pword, utf = mir_utf8encodeT(ws)); mir_free(utf);
 +
 +			BOOL translated;
 +			int port = GetDlgItemInt(hwndDlg, IDC_ED_PORT, &translated, FALSE);
 +			if (translated)
 +				proto->options.port = port;
 +
 +			proto->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)
 +					proto->options.client_id = id;
 +			} else
 +				proto->options.client_id = id;
 +
 +			if (IsDlgButtonChecked(hwndDlg, IDC_RAD_ERRMB)) proto->options.err_method = ED_MB;
 +			else if (IsDlgButtonChecked(hwndDlg, IDC_RAD_ERRBAL)) proto->options.err_method = ED_BAL;
 +			else if (IsDlgButtonChecked(hwndDlg, IDC_RAD_ERRPOP)) proto->options.err_method = ED_POP;
 +
 +			proto->options.add_contacts = (IsDlgButtonChecked(hwndDlg, IDC_CHK_ADDCONTACTS) != FALSE);
 +			proto->options.encrypt_session = (IsDlgButtonChecked(hwndDlg, IDC_RAD_ENC) != FALSE);
 +			proto->options.idle_as_away = (IsDlgButtonChecked(hwndDlg, IDC_CHK_IDLEAWAY) != FALSE);
 +
 +			proto->options.use_old_default_client_ver = (IsDlgButtonChecked(hwndDlg, IDC_CHK_OLDDEFAULTVER) != FALSE);
 +
 +			proto->SaveOptions();
 +
 +			return TRUE;
 +		}
 +		break;
 +
 +	case WM_DESTROY:
 +		break;
 +	}
 +
 +	return FALSE;
 +}
 +
 +int CSametimeProto::OptInit(WPARAM wParam, LPARAM lParam)
 +{
 +	OPTIONSDIALOGPAGE odp = { sizeof(odp) };
 +	odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
 +	odp.hInstance = hInst;
 +	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTNET);
 +	odp.ptszTitle = m_tszUserName;
 +	odp.ptszGroup = LPGENT("Network");
 +	odp.pfnDlgProc = DlgProcOptNet;
 +	odp.dwInitParam = (LPARAM)this;
 +	Options_AddPage(wParam, &odp);
 +	return 0;
 +}
 +
 +void CSametimeProto::LoadOptions()
 +{
 +	DBVARIANT dbv;
 +
 +	if (!db_get_utf(0, m_szModuleName, "ServerName", &dbv)) {
 +		strncpy(options.server_name, dbv.pszVal, LSTRINGLEN);
 +		db_free(&dbv);
 +	}
 +	if (!db_get_utf(0, m_szModuleName, "stid", &dbv)) {
 +		strncpy(options.id, dbv.pszVal, LSTRINGLEN);
 +		db_free(&dbv);
 +	}
 +	if (!db_get_utf(0, m_szModuleName, "Password", &dbv)) {
 +		strncpy(options.pword, dbv.pszVal, LSTRINGLEN);
 +		db_free(&dbv);
 +	}
 +
 +	options.port = db_get_dw(0, m_szModuleName, "ServerPort", DEFAULT_PORT);
 +	options.encrypt_session = (db_get_b(0, m_szModuleName, "EncryptSession", 0) == 1);
 +
 +	options.client_id = db_get_dw(0, m_szModuleName, "ClientID", DEFAULT_ID);
 +	options.use_old_default_client_ver = (db_get_b(0, m_szModuleName, "UseOldClientVer", 0) == 1);
 +
 +	options.get_server_contacts = (db_get_b(0, m_szModuleName, "GetServerContacts", 1) == 1);
 +	options.add_contacts = (db_get_b(0, m_szModuleName, "AutoAddContacts", 0) == 1);
 +	options.idle_as_away = (db_get_b(0, m_szModuleName, "IdleAsAway", 1) == 1);
 +
 +	// if popups not installed, will be changed to 'ED_BAL' (balloons) in main.cpp, modules loaded
 +	options.err_method = (ErrorDisplay)db_get_b(0, m_szModuleName, "ErrorDisplay", ED_POP);
 +	// 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;
 +
 +	debugLog(_T("LoadOptions() loaded: ServerName:len=[%d], id:len=[%d], pword:len=[%d]"), options.server_name == NULL ? -1 : strlen(options.server_name), options.id == NULL ? -1 : strlen(options.id), options.pword == NULL ? -1 : strlen(options.pword));
 +	debugLog(_T("LoadOptions() loaded: port=[%d], encrypt_session=[%d], client_id=[%d], use_old_default_client_ver=[%d]"), options.port, options.encrypt_session, options.client_id, options.use_old_default_client_ver);
 +	debugLog(_T("LoadOptions() loaded: get_server_contacts=[%d], add_contacts=[%d], idle_as_away=[%d], err_method=[%d]"), options.get_server_contacts, options.add_contacts, options.idle_as_away, options.err_method);
 +	
 +}
 +
 +void CSametimeProto::SaveOptions()
 +{
 +	db_set_utf(0, m_szModuleName, "ServerName", options.server_name);
 +
 +	db_set_utf(0, m_szModuleName, "stid", options.id);
 +	//db_set_s(0, m_szModuleName, "Nick", options.id);
 +	db_set_utf(0, m_szModuleName, "Password", options.pword);
 +
 +	db_set_dw(0, m_szModuleName, "ServerPort", options.port);
 +	db_set_b(0, m_szModuleName, "GetServerContacts", options.get_server_contacts ? 1 : 0);
 +	db_set_dw(0, m_szModuleName, "ClientID", options.client_id);
 +	db_set_b(0, m_szModuleName, "ErrorDisplay", options.err_method);
 +
 +	db_set_b(0, m_szModuleName, "AutoAddContacts", options.add_contacts ? 1 : 0);
 +	db_set_b(0, m_szModuleName, "EncryptSession", options.encrypt_session ? 1 : 0);
 +	db_set_b(0, m_szModuleName, "IdleAsAway", options.idle_as_away ? 1 : 0);
 +
 +	db_set_b(0, m_szModuleName, "UseOldClientVer", options.use_old_default_client_ver ? 1 : 0);
 +}
 diff --git a/protocols/Sametime/src/places.cpp b/protocols/Sametime/src/places.cpp new file mode 100644 index 0000000000..c7c0a19adf --- /dev/null +++ b/protocols/Sametime/src/places.cpp @@ -0,0 +1,67 @@ +#include "StdAfx.h"
 +#include "sametime.h"
 +
 +/* Stubs, NOT IMPLEMENTED NOW */
 +
 +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 CSametimeProto::InitPlaces(mwSession* session)
 +{
 +	debugLog(_T("CSametimeProto::InitPlaces()"));
 +	mwSession_addService(session, (mwService*)(service_places = mwServicePlace_new(session, &mwPlace_handler)));
 +}
 +
 +void CSametimeProto::DeinitPlaces(mwSession* session)
 +{
 +	debugLog(_T("CSametimeProto::DeinitPlaces()"));
 +	mwSession_removeService(session, mwService_PLACE);
 +	mwService_free((mwService*)service_places);
 +	service_places = 0;
 +}
 diff --git a/protocols/Sametime/src/resource.h b/protocols/Sametime/src/resource.h new file mode 100644 index 0000000000..3ca8cba566 --- /dev/null +++ b/protocols/Sametime/src/resource.h @@ -0,0 +1,59 @@ +//{{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_ICON_ANNOUNCE               107
 +#define IDI_ICON_NOTIFY                 108
 +#define IDI_ICON_ERROR                  109
 +#define IDD_SESSIONANNOUNCE             208
 +#define IDD_USERSEARCH                  209
 +#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/protocols/Sametime/src/sametime.cpp b/protocols/Sametime/src/sametime.cpp new file mode 100644 index 0000000000..5cec8f873a --- /dev/null +++ b/protocols/Sametime/src/sametime.cpp @@ -0,0 +1,296 @@ +#include "StdAfx.h"
 +#include "sametime.h"
 +#include "version.h"
 +
 +// plugin stuff
 +PLUGININFOEX pluginInfo={
 +	sizeof(PLUGININFOEX),
 +	__PLUGIN_NAME,
 +	PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
 +	__DESCRIPTION,
 +	__AUTHOR,
 +	__AUTHOREMAIL,
 +	__COPYRIGHT,
 +	__AUTHORWEB,
 +	UNICODE_AWARE,
 +	{ 0xf1b0ba1b, 0xc91, 0x4313, { 0x85, 0xeb, 0x22, 0x50, 0x69, 0xd4, 0x4d, 0x1 } } // {F1B0BA1B-0C91-4313-85EB-225069D44D01}
 +};
 +
 +
 +HINSTANCE hInst;
 +LIST<CSametimeProto> g_Instances(1, PtrKeySortT);
 +int hLangpack;
 +
 +
 +// sametime.cpp: Defines the entry point for the DLL application.
 +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 +{
 +	hInst = hinstDLL;
 +	return TRUE;
 +}
 +
 +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
 +{
 +	return &pluginInfo;
 +}
 +
 +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST};
 +
 +
 +
 +// protocol related services
 +
 +
 +/** 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_PTR CSametimeProto::GetName(WPARAM wParam, LPARAM lParam)
 +{
 +	strncpy((char*)lParam, m_szModuleName, wParam);
 +	return 0;
 +}
 +
 +/*
 + * Returns the current status
 + */
 +INT_PTR CSametimeProto::GetStatus(WPARAM wParam, LPARAM lParam)
 +{
 +	return m_iStatus;
 +}
 +
 +
 +/** 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_PTR CSametimeProto::SametimeLoadIcon(WPARAM wParam, LPARAM lParam)
 +{
 +	
 +	UINT id;
 +	switch (wParam & 0xFFFF)
 +	{
 +		case PLI_PROTOCOL:
 +			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;
 +}
 +
 +
 +//icolib stuff
 +static IconItem iconList[] =
 +{
 +	  { LPGEN("Protocol icon"), "protoicon", IDI_ICON_PROTO, 0 }
 +	, { LPGEN("Start Conference"), "leaveconference", IDI_ICON_INVITE, 0 }
 +	, { LPGEN("Leave Conference"), "startconference", IDI_ICON_LEAVE, 0 }
 +	, { LPGEN("Announce"), "announce", IDI_ICON_ANNOUNCE, 0 }
 +	, { LPGEN("Notification"), "notify", IDI_ICON_NOTIFY, 0 }
 +	, { LPGEN("Error"), "error", IDI_ICON_ERROR, 0 }
 +};
 +
 +void SametimeInitIcons(void)
 +{
 +	Icon_Register(hInst, "Protocols/Sametime", iconList, SIZEOF(iconList), "SAMETIME");
 +}
 +
 +HANDLE GetIconHandle(int iconId)
 +{
 +	for (int i = 0; i < SIZEOF(iconList); i++)
 +		if (iconList[i].defIconID == iconId)
 +			return iconList[i].hIcolib;
 +	return NULL;
 +}
 +
 +HICON LoadIconEx(const char* name, BOOL big)
 +{
 +	char szSettingName[100];
 +	mir_snprintf(szSettingName, sizeof(szSettingName), "%s_%s", "SAMETIME", name);
 +	return Skin_GetIcon(szSettingName, big);
 +}
 +
 +void ReleaseIconEx(const char* name, BOOL big)
 +{
 +	char szSettingName[100];
 +	mir_snprintf(szSettingName, sizeof(szSettingName), "%s_%s", "SAMETIME", name);
 +	Skin_ReleaseIcon(szSettingName, big);
 +}
 +
 +
 +// Copied from MSN plugin - sent acks need to be from different thread
 +void __cdecl sttFakeAckInfoSuccessThread(void* param)
 +{
 +	TFakeAckParams* tParam = (TFakeAckParams*)param;
 +	CSametimeProto* proto = tParam->proto;
 +	proto->debugLog(_T("sttFakeAckInfoSuccessThread() start"));
 +
 +	Sleep(100);
 +	proto->ProtoBroadcastAck(tParam->hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1, 0);
 +
 +	proto->debugLog(_T("sttFakeAckInfoSuccessThread() end"));
 +	mir_free(tParam);
 +	return;
 +}
 +
 +void __cdecl sttFakeAckMessageSuccessThread(void* param)
 +{
 +	TFakeAckParams* tParam = (TFakeAckParams*)param;
 +	CSametimeProto* proto = tParam->proto;
 +	proto->debugLog(_T("sttFakeAckMessageSuccessThread() start"));
 +
 +	Sleep(100);
 +	proto->ProtoBroadcastAck(tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)tParam->lParam, 0 );
 +
 +	proto->debugLog(_T("sttFakeAckMessageSuccessThread() end"));
 +	mir_free(tParam);
 +	return;
 +}
 +
 +void __cdecl sttFakeAckMessageFailedThread(void* param)
 +{
 +	TFakeAckParams* tParam = (TFakeAckParams*)param;
 +	CSametimeProto* proto = tParam->proto;
 +	proto->debugLog(_T("sttFakeAckMessageFailedThread() start"));
 +
 +	Sleep(100);
 +	proto->ProtoBroadcastAck(tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, NULL, tParam->lParam); ///TODO tParam->lParam: add error message
 +
 +	proto->debugLog(_T("sttFakeAckMessageFailedThread() end"));
 +	mir_free(tParam);
 +	return;
 +}
 +
 +void __cdecl sttRecvAwayThread(void* param)
 +{
 +	TFakeAckParams* tParam = (TFakeAckParams*)param;
 +	CSametimeProto* proto = tParam->proto;
 +	proto->debugLog(_T("sttRecvAwayThread() start"));
 +
 +	Sleep(100);
 +	proto->UserRecvAwayMessage(tParam->hContact);
 +
 +	proto->debugLog(_T("sttRecvAwayThread() end"));
 +	free(tParam);
 +	return;
 +}
 +
 +
 +int CSametimeProto::OnWindowEvent(WPARAM wParam, LPARAM lParam)
 +{
 +	MessageWindowEventData* mwed = (MessageWindowEventData*)lParam;
 +
 +	if (db_get_b(mwed->hContact, m_szModuleName, "ChatRoom", 0))
 +		return 0;
 +
 +	if (mwed && (mwed->uType == MSG_WINDOW_EVT_CLOSING || mwed->uType == MSG_WINDOW_EVT_CLOSE))
 +		CloseIm(mwed->hContact);
 +
 +	return 0;
 +}
 +
 +int CSametimeProto::OnIdleChanged(WPARAM wParam, LPARAM lParam)
 +{
 +	if (!(lParam & IDF_PRIVACY)) {
 +		is_idle = lParam & IDF_ISIDLE ? true : false;
 +		SetIdle(is_idle);
 +	}
 +
 +	return 0;
 +}
 +
 +
 +int CSametimeProto::OnPreShutdown(WPARAM wParam, LPARAM lParam)
 +{
 +	if (m_iStatus != ID_STATUS_OFFLINE){
 +		LogOut();
 +	}
 +
 +	return 0;
 +}
 +
 +
 +int CSametimeProto::OnSametimeContactDeleted(WPARAM wParam, LPARAM lParam)
 +{
 +	MCONTACT hContact = wParam;
 +	ContactDeleted(hContact);
 +	ChatDeleted(hContact);
 +	return 0;
 +}
 +
 +
 +void CSametimeProto::SetAllOffline()
 +{
 +	debugLog(_T("SetAllOffline() start"));
 +
 +	for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
 +		if (db_get_b(hContact, m_szModuleName, "ChatRoom", 0)) {
 +			CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0);
 +			continue;
 +		} else {
 +			db_set_w(hContact, m_szModuleName, "Status", ID_STATUS_OFFLINE);
 +			db_set_dw(hContact, m_szModuleName, "IdleTS", 0);
 +		}
 +	}
 +
 +}
 +
 +
 +void CSametimeProto::BroadcastNewStatus(int iNewStatus)
 +{
 +	if (m_iStatus == iNewStatus){
 +		return;
 +	}
 +
 +	debugLog(_T("BroadcastNewStatus() m_iStatus=[%d], iNewStatus=[%d]"), m_iStatus, iNewStatus);
 +
 +	previous_status = m_iStatus;
 +	m_iStatus = iNewStatus;
 +	ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)previous_status, m_iStatus);
 +}
 +
 +
 +static CSametimeProto* sametime_proto_init(const char* pszProtoName, const TCHAR* tszUserName)
 +{
 +	CSametimeProto* proto = new CSametimeProto(pszProtoName, tszUserName);
 +	g_Instances.insert(proto);
 +	return proto;
 +}
 +
 +static int sametime_proto_uninit(PROTO_INTERFACE* ppro)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)ppro;
 +	g_Instances.remove(proto);
 +	delete proto;
 +	return 0;
 +}
 +
 +extern "C" int __declspec(dllexport) Load(void)
 +{
 +
 +	PROTOCOLDESCRIPTOR pd = { sizeof(pd) };
 +	pd.type = PROTOTYPE_PROTOCOL;
 +	pd.szName = "Sametime";
 +	pd.fnInit = (pfnInitProto)sametime_proto_init;
 +	pd.fnUninit = (pfnUninitProto)sametime_proto_uninit;
 +	CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd);
 +
 +	return 0;
 +}
 +
 +extern "C" int __declspec(dllexport) Unload()
 +{
 +
 +	g_Instances.destroy();
 +
 +	return 0;
 +
 +}
 +
 diff --git a/protocols/Sametime/src/sametime.h b/protocols/Sametime/src/sametime.h new file mode 100644 index 0000000000..7554a5d78d --- /dev/null +++ b/protocols/Sametime/src/sametime.h @@ -0,0 +1,121 @@ +#ifndef _SAMETIME_H
 +#define _SAMETIME_H
 +
 +
 +//sametime defines
 +
 +#define FILE_BUFF_SIZE					(1024 * 32)
 +
 +#define MS_SAMETIME_MENULEAVECHAT		"/LeaveChat"
 +#define MS_SAMETIME_MENUCREATECHAT		"/CreateChat"
 +
 +#define MAX_MESSAGE_SIZE				(10 * 1024)				// verified limit in official client, thx Periferral
 +
 +#define LSTRINGLEN						256
 +
 +#define DEFAULT_PORT					1533
 +
 +#define WMU_STORECOMPLETE				(WM_USER + 110)
 +
 +
 +
 +typedef enum {SAMETIME_POPUP_ERROR = 1, SAMETIME_POPUP_INFO = 2 } SametimePopupEnum;
 +typedef enum {ED_MB = 1, ED_POP = 2, ED_BAL = 3} ErrorDisplay;
 +typedef enum {CPT_USER, CPT_ANSI, CPT_UTF8, CPT_OEM, CPT_UTF7} CodePageType;
 +
 +
 +
 +//stl typedef's
 +typedef std::queue<std::string> InviteQueue;					///for conference.cpp
 +typedef std::queue<std::string> MessageQueue;					///for messaging.cpp
 +typedef std::map<MCONTACT, MessageQueue> ContactMessageQueue;	///for messaging.cpp
 +
 +
 +//protocol includes
 +#include "resource.h"
 +
 +
 +//methods
 +INT_PTR CALLBACK SessionAnnounceDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 +INT_PTR CALLBACK CALLBACK SearchDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
 +void mwResolve_handler_callback(mwServiceResolve* srvc, guint32 id, guint32 code, GList* results, gpointer data);
 +
 +void SametimeInitIcons(void);
 +HANDLE GetIconHandle(int iconId);
 +HICON LoadIconEx(const char* name, BOOL big);
 +void ReleaseIconEx(const char* name, BOOL big);
 +
 +
 +// services (async thread functions)
 +void __cdecl sttFakeAckInfoSuccessThread(void* param);
 +void __cdecl sttFakeAckMessageFailedThread(void* param);
 +void __cdecl sttFakeAckMessageSuccessThread(void* param);
 +void __cdecl sttRecvAwayThread(void* param);
 +
 +
 +//sametime structs
 +
 +typedef struct Options_tag {
 +	char server_name[LSTRINGLEN]; // utf8
 +	char id[LSTRINGLEN];          // utf8
 +	char pword[LSTRINGLEN];       // utf8
 +	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;
 +} SametimeOptions;
 +
 +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;
 +
 +typedef struct FileTransferClientData_tag {
 +	char* save_path;
 +	HANDLE hFile;
 +	bool sending;
 +	MCONTACT hContact;
 +	struct FileTransferClientData_tag* first;
 +	struct FileTransferClientData_tag* next;
 +	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;
 +
 +
 +
 +// Global variables
 +struct CSametimeProto;
 +
 +extern HINSTANCE hInst;
 +extern PLUGININFOEX pluginInfo;
 +extern LIST<CSametimeProto> g_Instances;
 +
 +
 +#include "sametime_proto.h"
 +
 +
 +#endif //#ifndef _SAMETIME_H
 +
 diff --git a/protocols/Sametime/src/sametime_proto.cpp b/protocols/Sametime/src/sametime_proto.cpp new file mode 100644 index 0000000000..eb1839dc3a --- /dev/null +++ b/protocols/Sametime/src/sametime_proto.cpp @@ -0,0 +1,430 @@ +#include "StdAfx.h"
 +#include "sametime.h"
 +
 +
 +CSametimeProto::CSametimeProto(const char* pszProtoName, const TCHAR* tszUserName)
 +	: PROTO<CSametimeProto>(pszProtoName, tszUserName)
 +	, is_idle(false)
 +	, idle_status(false)
 +	, first_online(true)
 +	, idle_timerid(0)
 +	, session(NULL)
 +	, my_login_info(NULL)
 +	, my_conference(NULL)
 +	, service_places(NULL)
 +	, service_conference(NULL)
 +	, server_connection(0)
 +{
 +
 +	// Register m_hNetlibUser user
 +	TCHAR name[128];
 +	mir_sntprintf(name, SIZEOF(name), TranslateT("%s connection"), m_tszUserName);
 +	NETLIBUSER nlu = { 0 };
 +	nlu.cbSize = sizeof(nlu);
 +	nlu.flags = NUF_TCHAR | NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS;
 +	nlu.szSettingsModule = m_szModuleName;
 +	nlu.ptszDescriptiveName = name;
 +	m_hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);
 +
 +	RegisterGLibLogger();
 +	debugLog(_T("CSametimeProto::CSametimeProto() start  m_szModuleName=[%s], m_tszUserName=[%s]"), _A2T(m_szModuleName), m_tszUserName);
 +
 +	SametimeInitIcons();
 +	InitCritSection();
 +
 +	CreateProtoService(PS_GETNAME, &CSametimeProto::GetName);
 +	CreateProtoService(PS_GETSTATUS, &CSametimeProto::GetStatus);
 +	CreateProtoService(PS_LOADICON, &CSametimeProto::SametimeLoadIcon);
 +
 +	HookProtoEvent(ME_SYSTEM_PRESHUTDOWN, &CSametimeProto::OnPreShutdown);
 +	HookProtoEvent(ME_MSG_WINDOWEVENT, &CSametimeProto::OnWindowEvent);
 +	HookProtoEvent(ME_IDLE_CHANGED, &CSametimeProto::OnIdleChanged);
 +	HookProtoEvent(ME_DB_CONTACT_DELETED, &CSametimeProto::OnSametimeContactDeleted);
 +	HookProtoEvent(ME_OPT_INITIALISE, &CSametimeProto::OptInit);
 +
 +	// Initialize temporary DB settings
 +	db_set_resident(m_szModuleName, "Status");
 +	db_set_resident(m_szModuleName, "IdleTS");
 +
 +	RegisterPopups();
 +	InitAwayMsg();
 +
 +	mir_snprintf(szProtoGroups, SIZEOF(szProtoGroups), "%s_GROUPS", m_szModuleName);
 +
 +	m_iStatus = ID_STATUS_OFFLINE;
 +	previous_status = ID_STATUS_OFFLINE;
 +	SetAllOffline();
 +
 +	DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &mainThread, THREAD_SET_CONTEXT, FALSE, 0 );
 +
 +	InitConferenceMenu();
 +	InitSessionMenu();
 +	InitGroupChats();
 +
 +	LoadOptions();
 +
 +	debugLog(_T("CSametimeProto::CSametimeProto() end"));
 +}
 +
 +CSametimeProto::~CSametimeProto()
 +{
 +
 +	debugLog(_T("CSametimeProto::~CSametimeProto() start"));
 +
 +	DeinitSessionMenu();
 +	DeinitConferenceMenu();
 +
 +	DeinitAwayMsg();
 +	UnregisterPopups();
 +	DeinitCritSection();
 +
 +	debugLog(_T("CSametimeProto::~CSametimeProto() end"));
 +
 +	UnRegisterGLibLogger();
 +	Netlib_CloseHandle(m_hNetlibUser);
 +
 +}
 +
 +
 +MCONTACT CSametimeProto::AddToList(int flags, PROTOSEARCHRESULT* psr)
 +{
 +	MYPROTOSEARCHRESULT* sr = (MYPROTOSEARCHRESULT*)psr;
 +	debugLog(_T("CSametimeProto::AddToList()  flags=[%d]"), flags);
 +	return AddSearchedUser(sr, flags & PALF_TEMPORARY);
 +}
 +
 +MCONTACT CSametimeProto::AddToListByEvent(int flags, int iContact, HANDLE hDbEvent)
 +{
 +	debugLog(_T("CSametimeProto::AddToListByEvent()  flags=[%d]"), flags);
 +	return 0;
 +}
 +
 +
 +int CSametimeProto::Authorize(HANDLE hDbEvent)
 +{
 +	debugLog(_T("CSametimeProto::Authorize()"));
 +	return 1;
 +}
 +
 +int CSametimeProto::AuthDeny(HANDLE hDbEvent, const PROTOCHAR* szReason)
 +{
 +	debugLog(_T("CSametimeProto::AuthDeny()"));
 +	return 1;
 +}
 +
 +
 +int CSametimeProto::AuthRecv(MCONTACT hContact, PROTORECVEVENT*)
 +{
 +	debugLog(_T("CSametimeProto::AuthRecv()"));
 +	return 1;
 +}
 +
 +int CSametimeProto::AuthRequest(MCONTACT hContact, const PROTOCHAR* szMessage)
 +{
 +	debugLog(_T("CSametimeProto::AuthRequest()"));
 +	return 1;
 +}
 +
 +
 +HANDLE CSametimeProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szPath)
 +{
 +	debugLog(_T("CSametimeProto::FileAllow()  hContact=[%x], szPath=[%s]"), hContact, szPath);
 +	char* szPathA = mir_t2a(szPath);
 +	HANDLE res = AcceptFileTransfer(hContact, hTransfer, szPathA);
 +	mir_free(szPathA);
 +	return res;
 +}
 +
 +int CSametimeProto::FileCancel(MCONTACT hContact, HANDLE hTransfer)
 +{
 +	debugLog(_T("CSametimeProto::FileCancel()  hContact=[%x]"), hContact);
 +	CancelFileTransfer(hTransfer);
 +	return 0;
 +}
 +
 +int CSametimeProto::FileDeny(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szReason)
 +{
 +	debugLog(_T("CSametimeProto::FileDeny()  hContact=[%x], szReason=[%s]"), hContact, szReason);
 +	RejectFileTransfer(hTransfer);
 +	return 0;
 +}
 +
 +int CSametimeProto::FileResume(HANDLE hTransfer, int* action, const PROTOCHAR** szFilename)
 +{
 +	debugLog(_T("CSametimeProto::FileResume() action=[%d]"), &action);
 +	return 0;
 +}
 +
 +
 +DWORD_PTR CSametimeProto::GetCaps(int type, MCONTACT hContact)
 +{
 +	int ret = 0;
 +	switch (type) {
 +		case PFLAGNUM_1:
 +			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 | PF4_IMSENDUTF;
 +			break;
 +		case PFLAGNUM_5:
 +			ret = PF2_LIGHTDND;
 +			break;
 +		case PFLAG_UNIQUEIDTEXT:
 +			ret = (DWORD_PTR) Translate("Id");
 +			break;
 +		case PFLAG_MAXLENOFMESSAGE:
 +			ret = MAX_MESSAGE_SIZE;
 +			break;
 +		case PFLAG_UNIQUEIDSETTING:
 +			ret = (DWORD_PTR) "stid";
 +			break;
 +	}
 +	return ret;
 +}
 +
 +int CSametimeProto::GetInfo(MCONTACT hContact, int infoType)
 +{
 +	// GetInfo - retrieves a contact info
 +	debugLog(_T("CSametimeProto::GetInfo()  hContact=[%x], infoType=[%d]"), hContact, infoType);
 +	
 +	if (getByte(hContact, "ChatRoom", 0))
 +		return 1;
 +
 +	if (!session)
 +		return 1;
 +
 +	///TODO unimplemented - getting contact info
 +
 +	TFakeAckParams* tfap = (TFakeAckParams*)mir_alloc(sizeof(TFakeAckParams));
 +	tfap->proto = this;
 +	tfap->hContact = hContact;
 +	tfap->lParam = NULL;
 +	mir_forkthread(sttFakeAckInfoSuccessThread, (void*)tfap);
 +
 +	return 0;
 +}
 +
 +
 +HANDLE CSametimeProto::SearchBasic(const PROTOCHAR* id)
 +{
 +	debugLog(_T("CSametimeProto::SearchBasic()  id:len=[%d]"), id == NULL ? -1 : _tcslen(id));
 +	char* id_utf8 = mir_utf8encodeT(id);
 +	int ret = SearchForUser(id_utf8, FALSE);
 +	mir_free(id_utf8);
 +	return (HANDLE)ret;
 +	///TODO - add timeout (like at GGPROTO::searchthread)
 +}
 +
 +HANDLE CSametimeProto::SearchByEmail(const PROTOCHAR* email)
 +{
 +	return 0;
 +}
 +
 +HANDLE CSametimeProto::SearchByName(const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName)
 +{
 +	return 0;
 +}
 +
 +HWND CSametimeProto::SearchAdvanced(HWND owner)
 +{
 +	TCHAR buf[512];
 +	int ret = 0;
 +	if (GetDlgItemText(owner, IDC_EDIT1, buf, 512)) {
 +		debugLog(_T("CSametimeProto::SearchAdvanced()  buf:len=[%d]"), buf == NULL ? -1 : _tcslen(buf));
 +		char* buf_utf8 = mir_utf8encodeT(buf);
 +		ret = SearchForUser(buf_utf8, TRUE);
 +		mir_free(buf_utf8);
 +	}
 +	return (HWND)ret;
 +}
 +
 +HWND CSametimeProto::CreateExtendedSearchUI(HWND owner)
 +{
 +	debugLog(_T("CSametimeProto::CreateExtendedSearchUI() start"));
 +	return CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_USERSEARCH), owner, SearchDialogFunc, (LPARAM)this);
 +}
 +
 +
 +int CSametimeProto::RecvContacts(MCONTACT hContact, PROTORECVEVENT*)
 +{
 +	debugLog(_T("CSametimeProto::RecvContacts()"));
 +	return 1;
 +}
 +
 +int CSametimeProto::RecvFile(MCONTACT hContact, PROTOFILEEVENT* pre)
 +{
 +	debugLog(_T("CSametimeProto::RecvFile()  hContact=[%x]"), hContact);
 +
 +	db_unset(hContact, "CList", "Hidden");
 +	db_unset(hContact, "CList", "NotOnList");
 +
 +	return Proto_RecvFile(hContact, pre);
 +}
 +
 +int CSametimeProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT* pre)
 +{
 +	debugLog(_T("CSametimeProto::RecvMsg() hContact=[%x]"), hContact);
 +
 +	db_unset(hContact, "CList", "Hidden");
 +	db_unset(hContact, "CList", "NotOnList");
 +
 +	return Proto_RecvMessage(hContact, pre);
 +}
 +
 +int CSametimeProto::RecvUrl(MCONTACT hContact, PROTORECVEVENT*)
 +{
 +	debugLog(_T("CSametimeProto::RecvUrl()"));
 +	return 1;
 +}
 +
 +int CSametimeProto::SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT* hContactsList)
 +{
 +	debugLog(_T("CSametimeProto::SendContacts()    flags=[%d], nContacts=[%d]"), flags, nContacts);
 +	return 1;
 +}
 +
 +HANDLE CSametimeProto::SendFile(MCONTACT hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles)
 +{
 +	debugLog(_T("CSametimeProto::SendFile()  hContact=[%x]"), hContact);
 +	if (m_iStatus != ID_STATUS_OFFLINE) {
 +		if (hContact && ppszFiles && szDescription) {
 +			if (db_get_w(hContact, m_szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) {
 +				return SendFilesToUser(hContact, ppszFiles, szDescription);
 +			}
 +		}
 +	}
 +	return 0; // failure
 +}
 +
 +int CSametimeProto::SendMsg(MCONTACT hContact, int flags, const char* msg)
 +{
 +
 +	debugLog(_T("CSametimeProto::SendMsg()  hContact=[%x], flags=[%d]"), hContact, flags);
 +	char* proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
 +	int ret;
 +
 +	if (!proto || strcmp(proto, m_szModuleName) != 0 || db_get_w(hContact, m_szModuleName, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) {
 +		TFakeAckParams* tfap = (TFakeAckParams*)mir_alloc(sizeof(TFakeAckParams));
 +		tfap->proto = this;
 +		tfap->hContact = hContact;
 +		tfap->lParam = 0;
 +		mir_forkthread(sttFakeAckMessageFailedThread, (void*)tfap);
 +		return 0;
 +	}
 +
 +	char* msg_utf8;
 +	if (flags & PREF_UNICODE)
 +		msg_utf8 = mir_utf8encodeW((wchar_t*)&msg[ strlen( msg )+1 ] );
 +	else if (flags & PREF_UTF)
 +		msg_utf8 = mir_strdup(msg);
 +	else
 +		msg_utf8 = mir_utf8encode(msg);
 +
 +	if (!msg_utf8)
 +		return 0;
 +
 +	ret = (int)SendMessageToUser(hContact, msg_utf8);
 +	mir_free(msg_utf8);
 +
 +	TFakeAckParams* tfap = (TFakeAckParams*)mir_alloc(sizeof(TFakeAckParams));
 +	tfap->proto = this;
 +	tfap->hContact = hContact;
 +	tfap->lParam = (LPARAM)ret;
 +	mir_forkthread(sttFakeAckMessageSuccessThread, (void*)tfap);
 +
 +	return ret;
 +}
 +
 +int CSametimeProto::SendUrl(MCONTACT hContact, int flags, const char* url)
 +{
 +	debugLog(_T("CSametimeProto::SendUrl()"));
 +	return 1;
 +}
 +
 +
 +int CSametimeProto::SetApparentMode(MCONTACT hContact, int mode)
 +{
 +	debugLog(_T("CSametimeProto::SetApparentMode()    mode=[%d]"), mode);
 +	return 1;
 +}
 +
 +int CSametimeProto::SetStatus(int iNewStatus)
 +{
 +	debugLog(_T("CSametimeProto::SetStatus()  m_iStatus=[%d], m_iDesiredStatus=[%d], iNewStatus=[%d]"), m_iStatus, m_iDesiredStatus, iNewStatus);
 +	m_iDesiredStatus = iNewStatus;
 +	if (iNewStatus != ID_STATUS_OFFLINE) {
 +		if (m_iStatus == ID_STATUS_OFFLINE)
 +			LogIn(iNewStatus, m_hNetlibUser);
 +		else
 +			SetSessionStatus(iNewStatus);
 +	} else if (m_iStatus != ID_STATUS_OFFLINE && iNewStatus == ID_STATUS_OFFLINE) {
 +		LogOut();
 +	}
 +
 +	return 0;
 +}
 +
 +HANDLE CSametimeProto::GetAwayMsg(MCONTACT hContact)
 +{
 +	debugLog(_T("CSametimeProto::GetInfo()  hContact=[%x], m_iStatus=[%d]"), hContact, m_iStatus);
 +	if (hContact && m_iStatus != ID_STATUS_OFFLINE) {
 +		TFakeAckParams* tfap;
 +		tfap = (TFakeAckParams*)malloc(sizeof(TFakeAckParams));
 +		tfap->proto = this;
 +		tfap->hContact = hContact;
 +		mir_forkthread(sttRecvAwayThread, (void*)tfap);
 +		return (HANDLE)1;
 +	}
 +	return (HANDLE)0;
 +}
 +
 +int CSametimeProto::RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT* evt)
 +{
 +	debugLog(_T("CSametimeProto::RecvAwayMsg()  hContact=[%x], mode=[%d]"), hContact, mode);
 +
 +	if (evt->flags & PREF_UTF) {
 +		TCHAR* pszMsg = mir_utf8decodeT(evt->szMessage);
 +		ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)evt->lParam, (LPARAM)pszMsg);
 +		mir_free(pszMsg);
 +	} else {
 +		ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)evt->lParam, (LPARAM)(TCHAR*)_A2T(evt->szMessage));
 +	}
 +
 +	return 0;
 +}
 +
 +int CSametimeProto::SetAwayMsg(int iStatus, const PROTOCHAR* msg)
 +{
 +	debugLog(_T("CSametimeProto::SetAwayMsg()  iStatus=[%d], msg:len=[%d]"), iStatus, msg == NULL ? -1 :_tcslen(msg));
 +	SetSessionAwayMessage(iStatus, msg);
 +	return 0;
 +}
 +
 +
 +int CSametimeProto::UserIsTyping(MCONTACT hContact, int type)
 +{
 +	debugLog(_T("CSametimeProto::UserIsTyping()  hContact=[%x], type=[%d]"), hContact, type);
 +	SendTyping(hContact, type == PROTOTYPE_SELFTYPING_ON);
 +	return 0;
 +}
 +
 +
 +int CSametimeProto::OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam)
 +{
 +	switch(iEventType) {
 +	case EV_PROTO_ONOPTIONS: {
 +		debugLog(_T("CSametimeProto::OnEvent() EV_PROTO_ONOPTIONS"));
 +		OptInit(wParam, lParam);
 +		break;
 +		}
 +	}
 +
 +	return TRUE;
 +}
 +
 diff --git a/protocols/Sametime/src/sametime_proto.h b/protocols/Sametime/src/sametime_proto.h new file mode 100644 index 0000000000..16cbeb17b0 --- /dev/null +++ b/protocols/Sametime/src/sametime_proto.h @@ -0,0 +1,248 @@ +
 +#ifndef _SAMETIME_PROTO_H
 +#define _SAMETIME_PROTO_H
 +
 +
 +
 +struct CSametimeProto : public PROTO<CSametimeProto>
 +{
 +
 +	CSametimeProto(const char*, const TCHAR* );
 +	~CSametimeProto();
 +
 +	//====================================================================================
 +	// PROTO_INTERFACE
 +	//====================================================================================
 +
 +
 +	virtual	MCONTACT  __cdecl AddToList(int flags, PROTOSEARCHRESULT* psr);
 +	virtual	MCONTACT  __cdecl AddToListByEvent(int flags, int iContact, HANDLE hDbEvent);
 +
 +	virtual	int       __cdecl Authorize(HANDLE hDbEvent);
 +	virtual	int       __cdecl AuthDeny(HANDLE hDbEvent, const PROTOCHAR* szReason);
 +	virtual	int       __cdecl AuthRecv(MCONTACT hContact, PROTORECVEVENT*);
 +	virtual	int       __cdecl AuthRequest(MCONTACT hContact, const PROTOCHAR* szMessage);
 +
 +	virtual	HANDLE    __cdecl FileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szPath);
 +	virtual	int       __cdecl FileCancel(MCONTACT hContact, HANDLE hTransfer);
 +	virtual	int       __cdecl FileDeny(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szReason);
 +	virtual	int       __cdecl FileResume(HANDLE hTransfer, int* action, const PROTOCHAR** szFilename);
 +
 +	virtual	DWORD_PTR __cdecl GetCaps(int type, MCONTACT hContact = NULL);
 +	virtual	int       __cdecl GetInfo(MCONTACT hContact, int infoType);
 +
 +	virtual	HANDLE    __cdecl SearchBasic(const PROTOCHAR* id);
 +	virtual	HANDLE    __cdecl SearchByEmail(const PROTOCHAR* email);
 +	virtual	HANDLE    __cdecl SearchByName(const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName);
 +	virtual	HWND      __cdecl SearchAdvanced(HWND owner);
 +	virtual	HWND      __cdecl CreateExtendedSearchUI(HWND owner);
 +
 +	virtual	int       __cdecl RecvContacts(MCONTACT hContact, PROTORECVEVENT*);
 +	virtual	int       __cdecl RecvFile(MCONTACT hContact, PROTOFILEEVENT*);
 +	virtual	int       __cdecl RecvMsg(MCONTACT hContact, PROTORECVEVENT*);
 +	virtual	int       __cdecl RecvUrl(MCONTACT hContact, PROTORECVEVENT*);
 +
 +	virtual	int       __cdecl SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT* hContactsList);
 +	virtual	HANDLE    __cdecl SendFile(MCONTACT hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles);
 +	virtual	int       __cdecl SendMsg(MCONTACT hContact, int flags, const char* msg);
 +	virtual	int       __cdecl SendUrl(MCONTACT hContact, int flags, const char* url);
 +
 +	virtual	int       __cdecl SetApparentMode(MCONTACT hContact, int mode);
 +	virtual	int       __cdecl SetStatus(int iNewStatus);
 +
 +	virtual	HANDLE    __cdecl GetAwayMsg(MCONTACT hContact);
 +	virtual	int       __cdecl RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT* evt);
 +	virtual	int       __cdecl SetAwayMsg(int iStatus, const PROTOCHAR* msg);
 +
 +	virtual	int       __cdecl UserIsTyping(MCONTACT hContact, int type);
 +
 +	virtual	int       __cdecl OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam);
 +
 +
 +
 +	// sametime.cpp
 +	int __cdecl OnSametimeContactDeleted(WPARAM wParam, LPARAM lParam);
 +	INT_PTR __cdecl GetName(WPARAM wParam, LPARAM lParam);
 +	INT_PTR __cdecl GetStatus(WPARAM wParam, LPARAM lParam);
 +	INT_PTR __cdecl SametimeLoadIcon(WPARAM wParam, LPARAM lParam);
 +	int __cdecl OnWindowEvent(WPARAM wParam, LPARAM lParam);
 +	int __cdecl OnPreShutdown(WPARAM wParam, LPARAM lParam);
 +	int __cdecl OnIdleChanged(WPARAM wParam, LPARAM lParam);
 +	void SetAllOffline();
 +	void BroadcastNewStatus(int iNewStatus);
 +
 +	// messaging.cpp
 +	void InitMessaging();
 +	void DeinitMessaging();
 +	void SendTyping(MCONTACT hContact, bool typing);
 +	HANDLE SendMessageToUser(MCONTACT hContact, char* msg_utf8);
 +	void CloseIm(MCONTACT hContact);
 +
 +	// userlist.cpp
 +	int SearchForUser(const char* name, BOOLEAN advanced);
 +	MCONTACT AddSearchedUser(MYPROTOSEARCHRESULT* mpsr, bool temporary);
 +	MCONTACT AddContact(mwSametimeUser* user, bool temporary);
 +	bool GetAwareIdFromContact(MCONTACT hContact, mwAwareIdBlock* id_block);
 +	MCONTACT FindContactByUserId(const char* id);
 +	void ImportContactsFromList(mwSametimeList* user_list, bool temporary);
 +	void ImportContactsFromFile(TCHAR* filename);
 +	void ExportContactsToList(mwSametimeList* user_list);
 +	void ExportContactsToServer();
 +	void UserListAddStored();
 +	void InitUserList();
 +	void DeinitUserList();
 +	void SetContactGroup(MCONTACT hContact, const char* name);
 +	void AddGroup(const char* name, bool expanded);
 +	void UserListCreate();
 +	void UserListDestroy();
 +	int GetMoreDetails(const char* name);
 +	void UserRecvAwayMessage(MCONTACT hContact);
 +	int ContactDeleted(MCONTACT hContact);
 +
 +	// files.cpp
 +	void InitFiles();
 +	void DeinitFiles();
 +	HANDLE AcceptFileTransfer(MCONTACT hContact, HANDLE hFt, char* save_path);
 +	void RejectFileTransfer(HANDLE hFt);
 +	void CancelFileTransfer(HANDLE hFt);
 +	HANDLE SendFilesToUser(MCONTACT hContact, PROTOCHAR** files, const PROTOCHAR* pszDesc);
 +
 +	// conference.cpp
 +	void InitConference();
 +	void InitConferenceMenu();
 +	void DeinitConference();
 +	void DeinitConferenceMenu();
 +	void ClearInviteQueue();
 +	void TerminateConference(char* name);
 +	int __cdecl GcEventHook(WPARAM wParam, LPARAM lParam);
 +	int __cdecl PrebuildContactMenu(WPARAM wParam, LPARAM lParam);
 +	int ChatDeleted(MCONTACT hContact);
 +	INT_PTR __cdecl onMenuLeaveChat(WPARAM wParam, LPARAM lParam);
 +	INT_PTR __cdecl onMenuCreateChat(WPARAM wParam, LPARAM lParam);
 +
 +	// sametime_session.cpp
 +	void SessionStarted();
 +	void SessionStopping();
 +	void InitSessionMenu();
 +	void DeinitSessionMenu();
 +	int LogIn(int status, HANDLE hNetlibUser);
 +	int LogOut();
 +	void InitCritSection();
 +	void DeinitCritSection();
 +	int SetSessionStatus(int status);
 +	void UpdateSelfStatus();
 +	int SetIdle(bool idle);
 +	void SetSessionAwayMessage(int status, const PROTOCHAR* msg);
 +	WORD GetClientVersion();
 +	WORD GetServerVersion();
 +	INT_PTR __cdecl SessionAnnounce(WPARAM wParam, LPARAM lParam);
 +	void InitGroupChats();
 +	void InitAwayMsg();
 +	void DeinitAwayMsg();
 +	void InitMeanwhileServices();
 +	void DeinitMeanwhileServices();
 +
 +	// options.cpp
 +	int __cdecl OptInit(WPARAM wParam, LPARAM lParam);
 +	void LoadOptions();
 +	void SaveOptions();
 +
 +	// utils.cpp
 +	void showPopup(const TCHAR* msg, SametimePopupEnum flag);
 +	void RegisterPopups();
 +	void UnregisterPopups();
 +	void RegisterGLibLogger();
 +	void UnRegisterGLibLogger();
 +
 +	// places.cpp
 +	void InitPlaces(mwSession* session);
 +	void DeinitPlaces(mwSession* session);
 +
 +
 +
 +
 +	/* properties */
 +
 +	char szProtoGroups[128];
 +	HANDLE mainThread;
 +	CRITICAL_SECTION session_cs;
 +	mwSession* session;
 +	int previous_status;
 +	bool is_idle;
 +
 +	// userlist.cpp
 +	mwServiceStorage* service_storage;
 +	mwServiceAware* service_aware;
 +	mwServiceResolve* service_resolve;
 +	mwAwareList* aware_list;
 +
 +	// files.cpp
 +	mwServiceFileTransfer* service_files;
 +
 +	// messaging.cpp
 +	CRITICAL_SECTION q_cs;
 +	mwServiceIm* service_im;
 +	ContactMessageQueue contact_message_queue;
 +
 +	// sametime_session.cpp
 +	bool first_online; // set our status after the first online status comes from the server
 +	HANDLE hSessionAnnounceMenuItem;
 +	int login_status;
 +	bool idle_status;
 +	int idle_timerid;
 +	HANDLE server_connection;
 +
 +	// conference.cpp
 +	InviteQueue invite_queue;
 +	mwServiceConference* service_conference;
 +	mwLoginInfo* my_login_info;
 +	mwConference* my_conference;
 +	HANDLE hLeaveChatMenuItem;
 +	HANDLE hCreateChatMenuItem;
 +
 +	// options.cpp
 +	SametimeOptions options;
 +
 +	// places.cpp
 +	mwServicePlace* service_places;
 +
 +	// utils.cpp
 +	HANDLE hPopupError;
 +	HANDLE hPopupNotify;
 +	guint gLogHandler;
 +
 +};
 +
 +
 +
 +typedef struct tag_TFakeAckParams {
 +	CSametimeProto* proto;
 +	MCONTACT hContact;
 +	LPARAM lParam;
 +} TFakeAckParams;
 +
 +
 +struct SendAnnouncementFunc_arg {
 +	CSametimeProto* proto;
 +	TCHAR msg[MAX_MESSAGE_SIZE];
 +	GList* recipients;
 +};
 +
 +typedef void (*SendAnnouncementFunc)(SendAnnouncementFunc_arg* ad);
 +
 +struct SessionAnnounceDialogProc_arg {
 +	CSametimeProto* proto;
 +	SendAnnouncementFunc sendAnnouncementFunc;
 +};
 +
 +
 +struct PopupData {
 +	SametimePopupEnum flag;
 +	TCHAR* title;
 +	TCHAR* text;
 +	CSametimeProto* proto;
 +};
 +
 +
 +#endif //#ifndef _SAMETIME_PROTO_H
 +
 diff --git a/protocols/Sametime/src/sametime_session.cpp b/protocols/Sametime/src/sametime_session.cpp new file mode 100644 index 0000000000..bc03f86a03 --- /dev/null +++ b/protocols/Sametime/src/sametime_session.cpp @@ -0,0 +1,634 @@ +#include "StdAfx.h"
 +#include "sametime.h"
 +
 +/// not in CSametimeProto (used at NETLIBOPENCONNECTION_tag.waitcallback)
 +bool continue_connect;
 +
 +#define MS_SAMETIME_MENUANNOUNCESESSION		"/SessionAnnounce"
 +
 +// utf8 encoded
 +struct {
 +	char* szOnline;
 +	char* szAway;
 +	char* szDND;
 +} AwayMessages;
 +
 +
 +void __cdecl SessionClear(mwSession* session)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionClear()"));
 +}
 +
 +int __cdecl SessionWrite(mwSession* session, const unsigned char* buf, gsize len)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionWrite()  server_connection=[%d], len=[%d]"), proto->server_connection, len);
 +	if (!proto->server_connection) return 1;
 +	if (Netlib_Send(proto->server_connection, (const char*)buf, len, 0) == SOCKET_ERROR)
 +		return 1;
 +	return 0;
 +}
 +
 +void __cdecl SessionClose(mwSession* session)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionClose()  server_connection=[%d]"), proto->server_connection);
 +	Netlib_CloseHandle(proto->server_connection);
 +	proto->server_connection = 0;
 +}
 +
 +void CSametimeProto::SessionStarted()
 +{
 +	UserListCreate();
 +	if (options.get_server_contacts) UserListAddStored();
 +}
 +
 +void CSametimeProto::SessionStopping()
 +{
 +	UserListDestroy();
 +}
 +
 +void CSametimeProto::InitMeanwhileServices()
 +{
 +	debugLog(_T("InitMeanwhileServices() start"));
 +
 +	if (options.encrypt_session) {
 +		mwSession_addCipher(session, mwCipher_new_RC2_128(session));
 +		mwSession_addCipher(session, mwCipher_new_RC2_40(session));
 +	}
 +
 +	InitUserList();
 +	InitMessaging();
 +	InitFiles();
 +	InitConference();
 +
 +	mwSession_setProperty(session, "PROTO_STRUCT_PTR", this, NULL);
 +
 +	///TODO InitMeanwhileServices DeinitMeanwhileServices on LogIn LogOut, do not need restart
 +	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(db_get_w(0, m_szModuleName, "ClientVersionMajor", MW_PROTOCOL_VERSION_MAJOR)), 0);
 +		mwSession_setProperty(session, mwSession_CLIENT_VER_MINOR, GUINT_TO_POINTER(db_get_w(0, m_szModuleName, "ClientVersionMinor", MW_PROTOCOL_VERSION_MINOR)), 0);
 +	} else {
 +		mwSession_setProperty(session, mwSession_CLIENT_VER_MAJOR, GUINT_TO_POINTER(db_get_w(0, m_szModuleName, "ClientVersionMajor", 0x001e)), 0);
 +		mwSession_setProperty(session, mwSession_CLIENT_VER_MINOR, GUINT_TO_POINTER(db_get_w(0, m_szModuleName, "ClientVersionMinor", 0x196f)), 0);
 +	}
 +
 +}
 +
 +void CSametimeProto::DeinitMeanwhileServices()
 +{
 +	debugLog(_T("DeinitMeanwhileServices() start"));
 +	DeinitConference();
 +	DeinitFiles();
 +	DeinitMessaging();
 +	DeinitUserList();
 +	mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_40));
 +	mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_128));
 +}
 +
 +void __cdecl SessionStateChange(mwSession* session, mwSessionState state, gpointer info)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionStateChange()  state=[%d]"), state);
 +
 +	switch(state) {
 +
 +	case mwSession_STARTING:
 +		break;
 +
 +	case mwSession_HANDSHAKE:
 +		break;
 +
 +	case mwSession_HANDSHAKE_ACK:
 +		break;
 +
 +	case mwSession_STARTED: 
 +		proto->SessionStarted();
 +		break;
 +
 +	case mwSession_STOPPING:
 +		if ((int)info) {// & ERR_FAILURE) {
 +			char *msg = mwError((int)info);
 +			TCHAR *msgT = mir_utf8decodeT(msg);
 +			proto->showPopup(TranslateTS(msgT), SAMETIME_POPUP_ERROR);
 +			mir_free(msgT);
 +			g_free(msg);
 +		}
 +		proto->SessionStopping();
 +		break;
 +
 +	case mwSession_STOPPED:
 +		break;
 +		
 +	case mwSession_LOGIN_REDIR:
 +		proto->debugLog(_T("SessionStateChange()  mwSession_LOGIN_REDIR  info=[%s]"), _A2T((char*)info));
 +		//options.server_name = str((char*)info);
 +		strcpy(proto->options.server_name, (char*)info);
 +		proto->LogOut();
 +		proto->LogIn(proto->login_status, proto->m_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* session, const char* text)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionAdmin()"));
 +	TCHAR* tt = mir_utf8decodeT(text);
 +	MessageBox(0, tt, TranslateT("Sametime Administrator Message"), MB_OK);
 +	mir_free(tt);
 +}
 +
 +void __cdecl SessionAnnounce(struct mwSession* session, struct mwLoginInfo* from, gboolean may_reply, const char* text)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionAnnounce()"));
 +	TCHAR* stzFrom;
 +	TCHAR* stzText;
 +	TCHAR stzFromBuff[256];
 +	stzFrom = mir_utf8decodeT(from->user_name);
 +	stzText = mir_utf8decodeT(text);
 +	mir_sntprintf(stzFromBuff, 256, TranslateT("Session Announcement - from '%s'"), stzFrom);
 +	MessageBox(0, TranslateTS(stzText), stzFromBuff, MB_OK);
 +	mir_free(stzText);
 +	mir_free(stzFrom);
 +}
 +
 +void __cdecl SessionSetPrivacyInfo(struct mwSession* session)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionSetPrivacyInfo()"));
 +}
 +
 +void __cdecl SessionSetUserStatus(struct mwSession* session)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	
 +	int new_status;
 +	struct mwUserStatus us;
 +	mwUserStatus_clone(&us, mwSession_getUserStatus(session));
 +
 +	proto->debugLog(_T("SessionSetUserStatus()  us.status=[%d]"), us.status);
 +
 +	switch(us.status) {
 +
 +	case mwStatus_ACTIVE:
 +		new_status = ID_STATUS_ONLINE; 
 +		break;
 +
 +	case mwStatus_AWAY:
 +		new_status = ID_STATUS_AWAY; 
 +		if (proto->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
 +			proto->BroadcastNewStatus(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 (!proto->first_online && !proto->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:
 +		{
 +			TCHAR buff[512];
 +			mir_sntprintf(buff, 512, TranslateT("Unknown user status: %d"), us.status);
 +			proto->showPopup(buff, SAMETIME_POPUP_ERROR);
 +			proto->debugLog(buff);
 +		}
 +		mwUserStatus_clear(&us);
 +		// just go online...to prevent us getting stuck 'connecting'
 +		new_status = ID_STATUS_ONLINE;
 +		break;
 +
 +	}
 +
 +	proto->m_iDesiredStatus = new_status;
 +
 +	if (proto->first_online) {
 +		proto->first_online = false;
 +		//proto->showPopup(TranslateT("Setting login status"), SAMETIME_POPUP_INFO);
 +		proto->debugLog(_T("Setting login status"));
 +		proto->SetSessionStatus(proto->login_status);
 +	} else {
 +		proto->BroadcastNewStatus(new_status);
 +	}
 +
 +	mwUserStatus_clear(&us);
 +}
 +
 +void CSametimeProto::UpdateSelfStatus()
 +{
 +	EnterCriticalSection(&session_cs);
 +	if (session) SessionSetUserStatus(session);
 +	LeaveCriticalSection(&session_cs);
 +}
 +
 +int CSametimeProto::SetSessionStatus(int status)
 +{
 +	struct mwUserStatus us;
 +	debugLog(_T("SetSessionStatus() start  status=[%d]"), status);
 +
 +	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;
 +	}
 +
 +	debugLog(_T("SetSessionStatus() mwSession_setUserStatus  us.status=[%d], us.desc:len=[%d]"), us.status, us.desc == NULL ? -1 : strlen(us.desc));
 +	mwSession_setUserStatus(session, &us);
 +
 +	return 0;
 +}
 +
 +VOID CALLBACK IdleTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)idEvent;
 +
 +	KillTimer(0, proto->idle_timerid);
 +	proto->idle_timerid = 0;
 +
 +	if (proto->idle_status) {
 +		struct mwUserStatus us;
 +		us.time = (DWORD)time(0);
 +		us.status = mwStatus_IDLE;
 +		us.desc = 0;
 +		mwSession_setUserStatus(proto->session, &us);
 +	} else {
 +		proto->SetSessionStatus(proto->m_iStatus);
 +	}
 +}
 +
 +int CSametimeProto::SetIdle(bool idle)
 +{
 +	// set a timer, to wait for any autoaway module which might set our status 
 +	debugLog(_T("CSametimeProto::SetIdle()  idle=[%d], idle_status=[%d], idle_timerid=[%d]"), idle, idle_status, idle_timerid);
 +	if (idle && !idle_status) {
 +		idle_status = true;
 +		if (!idle_timerid) 
 +			idle_timerid = SetTimer(0, (UINT_PTR)this, 200, IdleTimerProc);
 +	} else if (idle_status) {
 +		idle_status = false;
 +		if (!idle_timerid) 
 +			idle_timerid = SetTimer(0, (UINT_PTR)this, 200, IdleTimerProc);
 +	}
 +	return 0;
 +}
 +
 +void CSametimeProto::SetSessionAwayMessage(int status, const PROTOCHAR* msgT)
 +{
 +	debugLog(_T("SetSessionAwayMessage() status=[%d], msgT:len=[%d]"), status, msgT == NULL ? -1 : _tcslen(msgT));
 +
 +	ptrA msg(mir_utf8encodeT(msgT));
 +	if (status == ID_STATUS_ONLINE) {
 +		mir_free(AwayMessages.szOnline);
 +		if (msg) {
 +			AwayMessages.szOnline = mir_strdup(msg);
 +		} else AwayMessages.szOnline = 0;
 +	} else if (status == ID_STATUS_AWAY) {
 +		mir_free(AwayMessages.szAway);
 +		if (msg) {
 +			AwayMessages.szAway = mir_strdup(msg);
 +		} else AwayMessages.szAway = 0;
 +	} else if (status == ID_STATUS_DND) {
 +		mir_free(AwayMessages.szDND);
 +		if (msg) {
 +			AwayMessages.szDND = mir_strdup(msg);
 +		} else AwayMessages.szDND = 0;
 +	} else 
 +		return; // unsupported status
 +
 +	if (session){
 +		SetSessionStatus(status); // update current away message
 +	}
 +}
 +
 +static VOID CALLBACK NullAPC (DWORD_PTR)
 +{
 +	// This function intentionally left blank
 +}
 +
 +void WakeThread(HANDLE hThread)
 +{
 +	QueueUserAPC(NullAPC, hThread, 0);
 +}
 +
 +void __cdecl KeepAliveThread(LPVOID param)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)param;
 +	int i = 120;
 +	proto->debugLog(_T("KeepAliveThread() start"));
 +
 +	while(1) {
 +		
 +		if (i <= 0){
 +			i = 120;
 +			// send keepalive every 120 * 250 = 30000[ms]
 +			if (mwSession_isStarted(proto->session) && proto->session){
 +				mwSession_sendKeepalive(proto->session);
 +			}
 +		}
 +		
 +		i--;
 +		
 +		SleepEx(250, TRUE);
 +		
 +		EnterCriticalSection(&(proto->session_cs));
 +		if (Miranda_Terminated() || !proto->session) {
 +			LeaveCriticalSection(&(proto->session_cs));
 +			proto->debugLog(_T("KeepAliveThread() end"));
 +			break;
 +		}
 +		LeaveCriticalSection(&(proto->session_cs));
 +	}
 +
 +	return;
 +}
 +
 +int waitcallback(unsigned int* timeout)
 +{
 +	return continue_connect ? 1 : 0;
 +}
 +
 +void __cdecl SessionThread(LPVOID param)
 +{
 +
 +	CSametimeProto* proto = (CSametimeProto*)param;
 +	HANDLE hNetlibUser = proto->m_hNetlibUser;
 +	proto->debugLog(_T("SessionThread() start"));
 +
 +	continue_connect = true;
 +
 +	//setup
 +	NETLIBOPENCONNECTION conn_data = {0};
 +	conn_data.cbSize = sizeof(NETLIBOPENCONNECTION);
 +	conn_data.flags = NLOCF_V2;
 +	conn_data.szHost = proto->options.server_name;
 +	conn_data.wPort = proto->options.port;
 +	conn_data.timeout = 20;
 +	conn_data.waitcallback = waitcallback;
 +
 +	proto->BroadcastNewStatus(ID_STATUS_CONNECTING);
 +
 +	proto->server_connection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hNetlibUser, (LPARAM)&conn_data);
 +
 +	if (!proto->server_connection) {
 +
 +		proto->BroadcastNewStatus(ID_STATUS_OFFLINE);
 +
 +		if (continue_connect) {
 +			// real timeout - not user cancelled
 +			proto->showPopup(TranslateT("No server connection!"), SAMETIME_POPUP_ERROR);
 +		}
 +
 +		proto->debugLog(_T("SessionThread() end, no server_connection, continue_connect=[%d]"), continue_connect);
 +		return;
 +	}
 +
 +	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(&proto->session_cs);
 +	proto->session = mwSession_new(&handler);
 +
 +	proto->InitMeanwhileServices();
 +
 +	mwSession_start(proto->session);
 +	LeaveCriticalSection(&proto->session_cs);
 +
 +	mir_forkthread(KeepAliveThread, (void*)proto);
 +
 +	unsigned char* recv_buffer = (unsigned char*)mir_alloc(1024 * 32);
 +	int bytes;
 +	//while(session && server_connection && mwSession_getState(session) != mwSession_STOPPED) {
 +	while(proto->server_connection) {// && session) {// && !mwSession_isStopped(session)) { // break on error
 +		bytes = Netlib_Recv(proto->server_connection, (char *)recv_buffer, 1024 * 32, 0);
 +		proto->debugLog(_T("SessionThread() Netlib_Recv'ed bytes=[%d]"), bytes);
 +
 +		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(&proto->session_cs);
 +			mwSession_recv(proto->session, recv_buffer, bytes);
 +			LeaveCriticalSection(&proto->session_cs);
 +		}
 +	}
 +	mir_free(recv_buffer);
 +
 +	EnterCriticalSection(&proto->session_cs);
 +	proto->DeinitMeanwhileServices();
 +	mwSession* old_session = proto->session;
 +	proto->session = 0; // kills keepalive thread, if awake
 +	mwSession_free(old_session);
 +	LeaveCriticalSection(&proto->session_cs);
 +
 +	proto->BroadcastNewStatus(ID_STATUS_OFFLINE);
 +	proto->SetAllOffline();
 +	proto->first_online = true;
 +
 +	proto->debugLog(_T("SessionThread() end"));
 +	return;
 +}
 +
 +WORD CSametimeProto::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 CSametimeProto::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 CSametimeProto::LogIn(int ls, HANDLE hNetlibUser)
 +{
 +	debugLog(_T("LogIn() start"));
 +
 +	EnterCriticalSection(&session_cs);
 +	if (session) {
 +		LeaveCriticalSection(&session_cs);
 +		debugLog(_T("LogIn() end, currently in session"));
 +		return 0;
 +	}
 +	LeaveCriticalSection(&session_cs);
 +
 +	login_status = ls;
 +
 +	mir_forkthread(SessionThread, (void*)this);
 +
 +	return 0;
 +}
 +
 +int CSametimeProto::LogOut()
 +{
 +	debugLog(_T("LogOut() start"));
 +	continue_connect = false;
 +
 +	EnterCriticalSection(&session_cs);
 +	if (session && server_connection && m_iStatus != ID_STATUS_OFFLINE && !mwSession_isStopped(session) && !mwSession_isStopping(session)) {
 +		debugLog(_T("LogOut() mwSession_stop"));
 +		mwSession_stop(session, 0);
 +	}
 +	LeaveCriticalSection(&session_cs);
 +	
 +	return 0;
 +}
 +
 +void CSametimeProto::InitAwayMsg()
 +{
 +	AwayMessages.szOnline = 0;
 +	AwayMessages.szAway = 0;
 +	AwayMessages.szDND = 0;
 +}
 +
 +void CSametimeProto::DeinitAwayMsg()
 +{
 +	mir_free(AwayMessages.szOnline);
 +	mir_free(AwayMessages.szAway);
 +	mir_free(AwayMessages.szDND);
 +}
 +
 +void SendAnnouncement(SendAnnouncementFunc_arg* arg)
 +{
 +	CSametimeProto* proto = arg->proto;
 +	char* utfs = mir_utf8encodeT(arg->msg);
 +	if (proto->session && arg->recipients) mwSession_sendAnnounce(proto->session, false , utfs, arg->recipients);
 +	mir_free(utfs);
 +}
 +
 +INT_PTR CSametimeProto::SessionAnnounce(WPARAM wParam, LPARAM lParam)
 +{
 +	debugLog(_T("CSametimeProto::SessionAnnounce() start"));
 +	SessionAnnounceDialogProc_arg* sadpArg = (SessionAnnounceDialogProc_arg*)mir_calloc(sizeof(SessionAnnounceDialogProc_arg));
 +	sadpArg->proto = this;
 +	sadpArg->sendAnnouncementFunc = SendAnnouncement;
 +	CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SESSIONANNOUNCE), GetDesktopWindow(), SessionAnnounceDialogProc, (LPARAM)sadpArg);
 +	return 0;
 +}
 +
 +void CSametimeProto::InitSessionMenu()
 +{
 +	debugLog(_T("CSametimeProto::InitSessionMenu()"));
 +
 +	CreateProtoService(MS_SAMETIME_MENUANNOUNCESESSION, &CSametimeProto::SessionAnnounce);
 +
 +	char service[128];
 +
 +	CLISTMENUITEM mi = { sizeof(mi) };
 +	mi.flags = CMIF_TCHAR;
 +	mi.popupPosition = 500085001;
 +	mi.position = 2000060000;
 +	mi.ptszName = LPGENT("Send Announcement...");
 +	mir_snprintf(service, sizeof(service), "%s%s", m_szModuleName, MS_SAMETIME_MENUANNOUNCESESSION);
 +	mi.pszService = service;
 +	mi.icolibItem = GetIconHandle(IDI_ICON_ANNOUNCE);
 +	mi.pszContactOwner = m_szModuleName;
 +	hSessionAnnounceMenuItem = Menu_AddContactMenuItem(&mi);
 +}
 +
 +void CSametimeProto::DeinitSessionMenu()
 +{
 +	debugLog(_T("CSametimeProto::DeinitSessionMenu()"));
 +	CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hSessionAnnounceMenuItem, (LPARAM)0);
 +}
 +
 +void CSametimeProto::InitCritSection()
 +{
 +	debugLog(_T("CSametimeProto::InitCritSection()"));
 +	InitializeCriticalSection(&session_cs);
 +}
 +
 +void CSametimeProto::DeinitCritSection()
 +{
 +	debugLog(_T("CSametimeProto::DeinitCritSection()"));
 +	DeleteCriticalSection(&session_cs);
 +}
 +
 +void CSametimeProto::InitGroupChats()
 +{
 +	debugLog(_T("CSametimeProto::InitGroupChats()"));
 +
 +	// register with chat module
 +	GCREGISTER gcr = { sizeof(gcr) };
 +	gcr.pszModule = m_szModuleName;
 +	gcr.ptszDispName = m_tszUserName;
 +	gcr.dwFlags = 0;
 +	gcr.iMaxText = MAX_MESSAGE_SIZE;
 +	gcr.nColors = 0;
 +	gcr.pColors = 0;
 +	CallService(MS_GC_REGISTER, 0, (LPARAM)(GCREGISTER*) &gcr);
 +}
 diff --git a/protocols/Sametime/src/session_announce_win.cpp b/protocols/Sametime/src/session_announce_win.cpp new file mode 100644 index 0000000000..8cf9cecb8f --- /dev/null +++ b/protocols/Sametime/src/session_announce_win.cpp @@ -0,0 +1,147 @@ +#include "StdAfx.h"
 +#include "sametime.h"
 +
 +INT_PTR CALLBACK SessionAnnounceDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 +
 +	SessionAnnounceDialogProc_arg* arg = (SessionAnnounceDialogProc_arg*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +	CSametimeProto* proto;
 +	if (arg != NULL) proto = arg->proto;
 +
 +	switch(uMsg) {
 +		case WM_INITDIALOG: {
 +
 +			TranslateDialogDefault(hwndDlg);
 +
 +			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
 +			SessionAnnounceDialogProc_arg* arg = (SessionAnnounceDialogProc_arg*)lParam;
 +			proto = arg->proto;
 +			proto->debugLog(_T("SessionAnnounceDialogProc WM_INITDIALOG"));
 +
 +			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; 
 +				lvI.iItem=0;
 +				lvI.iSubItem=0;
 +
 +				for (MCONTACT hContact = db_find_first(proto->m_szModuleName); hContact; hContact = db_find_next(hContact, proto->m_szModuleName)) {
 +					if (db_get_b(hContact, proto->m_szModuleName, "ChatRoom", 0) == 0
 +						&& db_get_w(hContact, proto->m_szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) 
 +					{
 +						lvI.lParam = (LPARAM)hContact;
 +						lvI.pszText = (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR);
 +						ListView_InsertItem(GetDlgItem(hwndDlg, IDC_LST_ANTO), &lvI);
 +						lvI.iItem++;
 +					}
 +				}
 +			}
 +
 +			return 0;
 +			}
 +
 +		case WM_CLOSE:
 +			proto->debugLog(_T("SessionAnnounceDialogProc WM_CLOSE"));
 +			mir_free(arg);
 +			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: {
 +							proto->debugLog(_T("SessionAnnounceDialogProc IDOK BN_CLICKED"));
 +							// build SendAnnouncementFunc_arg
 +							SendAnnouncementFunc_arg* safArg = (SendAnnouncementFunc_arg*)mir_calloc(sizeof(SendAnnouncementFunc_arg));
 +							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
 +							safArg->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 (!db_get_utf((MCONTACT)lvI.lParam, proto->m_szModuleName, "stid", &dbv)) {
 +										safArg->recipients = g_list_prepend(safArg->recipients, _strdup(dbv.pszVal));
 +										strcpy(p, dbv.pszVal);
 +										safArg->recipients = g_list_prepend(safArg->recipients, _strdup(id));
 +										send_count++;
 +										db_free(&dbv);
 +									}
 +								}
 +							}
 +
 +							if (send_count > 0) {
 +								GetWindowText(GetDlgItem(hwndDlg, IDC_ED_ANMSG), safArg->msg, MAX_MESSAGE_SIZE);
 +								safArg->proto = proto;
 +								SendAnnouncementFunc sendAnnouncementFunc = arg->sendAnnouncementFunc;
 +								sendAnnouncementFunc(safArg);
 +							}
 +
 +							// clean up recipient list
 +							if (safArg->recipients){
 +								for (GList *rit = safArg->recipients; rit; rit = rit->next) {
 +									free(rit->data);
 +								}
 +								g_list_free(safArg->recipients);
 +							}
 +
 +							DestroyWindow(hwndDlg);
 +						}
 +						return 0;
 +
 +					case IDCANCEL:
 +						DestroyWindow(hwndDlg);
 +						return 0;
 +				}
 +			}
 +			break;
 +	}
 +
 +	return 0;
 +}
\ No newline at end of file diff --git a/protocols/Sametime/src/userlist.cpp b/protocols/Sametime/src/userlist.cpp new file mode 100644 index 0000000000..89e11a0a81 --- /dev/null +++ b/protocols/Sametime/src/userlist.cpp @@ -0,0 +1,836 @@ +#include "StdAfx.h"
 +#include "sametime.h"
 +
 +MCONTACT CSametimeProto::FindContactByUserId(const char* id)
 +{
 +	DBVARIANT dbv;
 +	for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
 +		if (!db_get_utf(hContact, m_szModuleName, "stid", &dbv)) {
 +			if (dbv.pszVal && strcmp(id, dbv.pszVal) == 0) {
 +				db_free(&dbv);
 +				return hContact;
 +			}
 +			db_free(&dbv);
 +		}
 +	}
 +	return 0;
 +}
 +
 +bool CSametimeProto::GetAwareIdFromContact(MCONTACT hContact, mwAwareIdBlock* id_block)
 +{
 +	char* proto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 );
 +	DBVARIANT dbv;
 +	if ( proto && !strcmp(m_szModuleName, proto)) {
 +		if (!db_get_utf(hContact, m_szModuleName, "stid", &dbv)) {
 +			if (dbv.pszVal) {
 +				id_block->type = mwAware_USER;
 +				id_block->user = _strdup(dbv.pszVal);
 +				id_block->community = 0;
 +				db_free(&dbv);
 +				return true;
 +			}
 +			db_free(&dbv);
 +		}
 +	}
 +	return false;
 +}
 +
 +void CSametimeProto::SetContactGroup(MCONTACT hContact, const char* name)
 +{
 +	db_set_utf(hContact, "CList", "Group", name);
 +}
 +
 +void CSametimeProto::AddGroup(const char* name, bool expanded)
 +{
 +	if (name && strcmp(name, "MetaContacts Hidden Group") == 0)
 +		return;
 +
 +	if (name && strcmp(name, Translate("None")) == 0)
 +		return;
 +
 +	ptrT ptszGroup(mir_utf8decodeT(name));
 +	HANDLE hGroup = Clist_GroupExists(ptszGroup);
 +	if (hGroup == NULL) {
 +		hGroup = Clist_CreateGroup(NULL, ptszGroup);
 +		if (hGroup) {
 +			CallService(MS_CLUI_GROUPADDED, (WPARAM)hGroup, 0);
 +			CallService(MS_CLIST_GROUPSETEXPANDED, (WPARAM)hGroup, expanded ? 1 : 0);
 +		}
 +	}
 +}
 +
 +MCONTACT CSametimeProto::AddContact(mwSametimeUser* user, bool temporary) 
 +{
 +
 +	debugLog(_T("CSametimeProto::AddContact() start"));
 +	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);
 +
 +	MCONTACT hContact = FindContactByUserId(id);
 +	bool new_contact = false;
 +	if (!hContact) {
 +		hContact = (MCONTACT)CallService(MS_DB_CONTACT_ADD, 0, 0);
 +		if (!hContact) {
 +			debugLog(_T("AddContact(): Failed to create Sametime contact"));
 +			return NULL; ///TODO error handling
 +		}
 +		if (CallService(MS_PROTO_ADDTOCONTACT, (WPARAM) hContact, (LPARAM) m_szModuleName) != 0) {
 +			CallService(MS_DB_CONTACT_DELETE, (WPARAM) hContact, 0);
 +			debugLog(_T("AddContact(): Failed to register Sametime contact"));
 +			return NULL; ///TODO error handling
 +		}
 +		new_contact = true;
 +	} else if (!temporary) {
 +		db_unset(hContact, "CList", "NotOnList");
 +		db_unset(hContact, "CList", "Hidden");
 +	}
 +
 +
 +	// add to miranda
 +	if (new_contact) db_set_utf(hContact, m_szModuleName, "stid", id);
 +
 +	if (name && strlen(name))
 +		db_set_utf(hContact, m_szModuleName, "Name", name);
 +
 +	if (nick && strlen(nick)) {
 +		db_set_utf(hContact, m_szModuleName, "Nick", nick);
 +	} else if (name && strlen(name)) {
 +		db_set_utf(hContact, m_szModuleName, "Nick", name);
 +	} else {
 +		db_set_utf(hContact, m_szModuleName, "Nick", id);
 +	}
 +
 +	db_set_b(hContact, m_szModuleName, "type", (BYTE)type);
 +
 +	if (new_contact) {
 +		//add to our awareness list
 +		mwAwareIdBlock id_block;
 +		if (GetAwareIdFromContact(hContact, &id_block)) {
 +			GList* gl = g_list_prepend(NULL, &id_block);
 +			mwAwareList_addAware(aware_list, gl);
 +			g_list_free(gl);  
 +			free(id_block.user);
 +		}
 +	}
 +
 +	if (temporary) {
 +		db_set_b(hContact, "CList", "NotOnList", 1);
 +		db_set_b(hContact, "CList", "Hidden", 1);
 +	} else {
 +		db_unset(hContact, "CList", "NotOnList");
 +		db_unset(hContact, "CList", "Hidden");
 +	}
 +
 +	return hContact;
 +}
 +
 +void CSametimeProto::ImportContactsFromList(mwSametimeList* user_list, bool temporary)
 +{
 +	debugLog(_T("CSametimeProto::ImportContactsFromList() start"));
 +	// 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, SIZEOF(buff), "GN_%s", group_alias);
 +		db_set_utf(0, szProtoGroups, buff, group_name);
 +		mir_snprintf(buff, SIZEOF(buff), "GT_%s", group_alias);
 +		db_set_b(0, szProtoGroups, buff, (BYTE)group_type);
 +		mir_snprintf(buff, SIZEOF(buff), "GO_%s", group_alias);
 +		db_set_b(0, szProtoGroups, buff, (BYTE)(group_open ? 1 : 0));
 +
 +		// inverse mapping
 +		mir_snprintf(buff, SIZEOF(buff), "GA_%s", group_name);
 +		db_set_utf(0, szProtoGroups, 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 = 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;
 +			MCONTACT 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 CSametimeProto::ExportContactsToList(mwSametimeList* user_list)
 +{
 +	debugLog(_T("CSametimeProto::ExportContactsToList() start"));
 +	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;
 +	DBVARIANT dbv, dbv2;
 +	char buff[256];
 +	mwAwareIdBlock id_block;
 +	mwIdBlock uid;
 +
 +	GList* gl = 0;
 +	for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
 +		if (!db_get_utf(hContact, m_szModuleName, "stid", &dbv)) {
 +			if (dbv.pszVal) {
 +				if (GetAwareIdFromContact(hContact, &id_block)) {
 +					if (!db_get_utf(hContact, "CList", "Group", &dbv2)) {
 +						group_alias = _strdup(dbv2.pszVal);
 +						db_free(&dbv2);
 +					} else
 +						group_alias = _strdup(Translate("None"));
 +
 +					if (group_alias) {
 +						mir_snprintf(buff, SIZEOF(buff), "GT_%s", group_alias);
 +						group_type = (mwSametimeGroupType)db_get_b(0, szProtoGroups, 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) {
 +							db_free(&dbv);
 +							free(id_block.user);
 +							free(group_alias);
 +							hContact = db_find_next(hContact, m_szModuleName);
 +							continue;
 +						}
 +
 +						mir_snprintf(buff, SIZEOF(buff), "GN_%s", group_alias);
 +						if (!db_get_utf(0, szProtoGroups, buff, &dbv2)) {
 +							group_name = _strdup(dbv2.pszVal);
 +							db_free(&dbv2);
 +						} else
 +							group_name = _strdup(group_alias);
 +						
 +						//group_open = (db_get_b(0, szProtoGroups, buff, 0) == 1);
 +
 +						ptrT ptszGroup(mir_utf8decodeT(group_alias));
 +						HANDLE hGroup = Clist_GroupExists(ptszGroup);
 +						if (hGroup) {
 +							int expanded;
 +							CallService(MS_CLIST_GROUPGETNAME, (WPARAM)hGroup, (LPARAM)&expanded);
 +							group_open = (expanded != 0);
 +						} else {
 +							mir_snprintf(buff, SIZEOF(buff), "GO_%s", group_alias);
 +							group_open = (db_get_b(0, szProtoGroups, 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 (!db_get_utf(hContact, m_szModuleName, "Name", &dbv2)) {
 +							user_shortName = _strdup(dbv2.pszVal);
 +							db_free(&dbv2);
 +						} else
 +							user_shortName = 0;
 +
 +						if (!db_get_utf(hContact, "CList", "MyHandle", &dbv2)) {
 +							user_alias = _strdup(dbv2.pszVal);
 +							db_free(&dbv2);
 +						} else
 +							user_alias = 0;
 +
 +						user_type = (mwSametimeUserType)db_get_b(hContact, m_szModuleName, "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);
 +				}
 +			}
 +			db_free(&dbv);
 +		}
 +	}
 +}
 +
 +void CSametimeProto::ImportContactsFromFile(TCHAR* filename)
 +{
 +	debugLog(_T("CSametimeProto::ImportContactsFromFile() start"));
 +	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);
 +
 +	}
 +}
 +
 +void CSametimeProto::ExportContactsToServer()
 +{
 +	mwSametimeList* user_list;
 +	mwStorageUnit* unit;
 +	mwPutBuffer* buff;
 +	mwOpaque* op;
 +
 +	debugLog(_T("CSametimeProto::ExportContactsToServer() start"));
 +	if (MW_SERVICE_IS_DEAD(service_storage)) {
 +		debugLog(_T("CSametimeProto::ExportContactsToServer() Failed"));
 +		showPopup(TranslateT("Failed to upload contacts - Storage service unavailable."), SAMETIME_POPUP_ERROR);
 +		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);
 +}
 +
 +
 +CSametimeProto* getProtoFromMwServiceStorage(mwServiceStorage* srvcStorage)
 +{
 +	mwService* service = mwServiceStorage_getService(srvcStorage);
 +	mwSession* session = mwService_getSession(service);
 +	return (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +}
 +
 +void load_users_callback(mwServiceStorage* srvc, guint32 result, mwStorageUnit *item, gpointer data)
 +{
 +	CSametimeProto* proto = getProtoFromMwServiceStorage(srvc);
 +
 +	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);
 +			proto->ImportContactsFromList(user_list, false);
 +			mwSametimeList_free(user_list);
 +		}
 +	}
 +}
 +
 +void CSametimeProto::UserListAddStored()
 +{
 +	mwStorageUnit* unit;
 +	unit = mwStorageUnit_new(mwStore_AWARE_LIST);
 +	mwServiceStorage_load(service_storage, unit, &load_users_callback, (gpointer)this, 0);
 +}
 +
 +int CSametimeProto::ContactDeleted(MCONTACT hContact)
 +{
 +	mwAwareIdBlock id_block;
 +	
 +	if (db_get_b(hContact, m_szModuleName, "ChatRoom", 0))
 +		return 0;
 +
 +	debugLog(_T("CSametimeProto::ContactDeleted()"));
 +
 +	if (GetAwareIdFromContact(hContact, &id_block)) {
 +		GList* gl = g_list_prepend(NULL, &id_block);
 +		mwAwareList_removeAware(aware_list, gl);
 +		g_list_free(gl);
 +		free(id_block.user);
 +	}
 +
 +	return 0;
 +}
 +
 +CSametimeProto* getProtoFromMwServiceResolve(mwServiceResolve* srvcResolve)
 +{
 +	mwService* service = mwServiceResolve_getService(srvcResolve);
 +	mwSession* session = mwService_getSession(service);
 +	return (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +}
 +
 +
 +void mwResolve_handler_dyngroup_callback(mwServiceResolve* srvc, guint32 id, guint32 code, GList *results, gpointer data)
 +{
 +	CSametimeProto* proto = getProtoFromMwServiceResolve(srvc);
 +	mwSametimeGroup* stgroup = (mwSametimeGroup*)data;
 +
 +	mwResolveResult* result;
 +	mwResolveMatch* match;
 +	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);
 +
 +				MCONTACT hContact = proto->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")) {
 +					proto->SetContactGroup(hContact, group_alias);
 +				}
 +			}
 +		}
 +	}
 +
 +	if (stgroup)
 +		mwSametimeList_free(mwSametimeGroup_getList(stgroup));
 +}
 +
 +
 +CSametimeProto* getProtoFromMwAwareList(mwAwareList* list)
 +{
 +	mwServiceAware* servAwere = mwAwareList_getServiceAware(list);
 +	mwService* service = mwServiceAware_getService(servAwere);
 +	mwSession* session = mwService_getSession(service);
 +	return (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +}
 +
 +void mwAwareList_on_aware(mwAwareList* list, mwAwareSnapshot* aware)
 +{
 +	CSametimeProto* proto = getProtoFromMwAwareList(list);;
 +
 +	MCONTACT hContact = proto->FindContactByUserId(aware->id.user);
 +	char* group = 0;
 +	DBVARIANT dbv;
 +	
 +	// update self - necessary for some servers
 +	if (aware->online && !db_get_utf(0, proto->m_szModuleName, "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);
 +			proto->UpdateSelfStatus();
 +
 +		db_free(&dbv);
 +	}
 +
 +	if (hContact && !db_get_utf(hContact, "CList", "Group", &dbv)) {
 +		group = _strdup(dbv.pszVal);
 +		db_free(&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, SIZEOF(buff), "GA_%s", aware->group);
 +		if (!db_get_utf(0, proto->szProtoGroups, buff, &dbv)) {
 +			mwSametimeGroup_setAlias(stgroup, dbv.pszVal);
 +			db_free(&dbv);
 +		}
 +
 +		GList* query = g_list_prepend(0, (void*)aware->id.user);
 +		mwServiceResolve_resolve(proto->service_resolve, query, mwResolveFlag_USERS, mwResolve_handler_dyngroup_callback, (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; 
 +				db_set_dw(hContact, proto->m_szModuleName, "IdleTS", 0);
 +				db_set_w(hContact, proto->m_szModuleName, "Status", new_status);
 +				break;
 +			case mwStatus_AWAY:
 +				new_status = ID_STATUS_AWAY; 
 +				db_set_dw(hContact, proto->m_szModuleName, "IdleTS", 0);
 +				db_set_w(hContact, proto->m_szModuleName, "Status", new_status);
 +				break;
 +			case mwStatus_IDLE:
 +				if (proto->options.idle_as_away) {
 +					new_status = ID_STATUS_AWAY;
 +					db_set_w(hContact, proto->m_szModuleName, "Status", new_status);
 +				}
 +				db_set_dw(hContact, proto->m_szModuleName, "IdleTS", (DWORD)time(0));
 +				break;
 +			case mwStatus_BUSY:
 +				new_status = ID_STATUS_DND; 
 +				db_set_w(hContact, proto->m_szModuleName, "Status", new_status);
 +				db_set_dw(hContact, proto->m_szModuleName, "IdleTS", 0);
 +				break;
 +			}
 +		} else
 +			db_set_w(hContact, proto->m_szModuleName, "Status", ID_STATUS_OFFLINE);
 +
 +		if (proto->service_aware) {
 +			const char* desc = mwServiceAware_getText(proto->service_aware, &aware->id);
 +			if (desc)
 +				//db_set_utf(hContact, m_szModuleName, "StatusMsg", desc);
 +				db_set_utf(hContact, "CList", "StatusMsg", desc);
 +			else
 +				//db_set_utf(hContact, m_szModuleName, "StatusMsg", "");
 +				//db_unset(hContact, m_szModuleName, "StatusMsg");
 +				db_unset(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 CSametimeProto::UserListCreate()
 +{
 +	debugLog(_T("CSametimeProto::UserListCreate() start"));
 +	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
 +
 +	DBVARIANT dbv;
 +	mwAwareIdBlock id_block;
 +	GList *gl = 0;
 +
 +	for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
 +		if (db_get_b(hContact, m_szModuleName, "ChatRoom", 0) == 0 /*&&  proto && !strcmp( PROTO, proto)*/) {
 +			if (!db_get_utf(hContact, m_szModuleName, "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);
 +					}
 +				}
 +				db_free(&dbv);
 +			}
 +		}
 +	}
 +
 +	// add self - might be necessary for some servers
 +	if (!db_get_utf(0, m_szModuleName, "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);
 +
 +		db_free(&dbv);
 +	}
 +}
 +
 +void CSametimeProto::UserListDestroy()
 +{
 +	mwAwareList_free(aware_list);
 +	aware_list = 0;
 +}
 +
 +void CSametimeProto::UserRecvAwayMessage(MCONTACT hContact)
 +{
 +	debugLog(_T("CSametimeProto::UserRecvAwayMessage() start hContact=[%x]"), hContact);
 +	DBVARIANT dbv;
 +	if (!db_get_s((MCONTACT)hContact, "CList", "StatusMsg", &dbv, DBVT_TCHAR)) {
 +		ProtoBroadcastAck((MCONTACT)hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)dbv.ptszVal);
 +		db_free(&dbv);
 +	} else {
 +		ProtoBroadcastAck((MCONTACT)hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)NULL);
 +	}
 +}
 +
 +void mwResolve_handler_callback(mwServiceResolve* srvc, guint32 id, guint32 code, GList* results, gpointer data)
 +{
 +	CSametimeProto* proto = getProtoFromMwServiceResolve(srvc);
 +	BOOL advanced = (BOOL)data;
 +
 +	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 == TRUE) {
 +		// 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);
 +		proto->ProtoBroadcastAck(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 == TRUE) 
 +					proto->ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, (HANDLE)id, (LPARAM)&mcsr);
 +				else
 +					proto->ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)id, (LPARAM)&mcsr.psr);
 +			}
 +		}
 +		proto->ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)id, 0);
 +	}
 +}
 +
 +
 +void mwResolve_handler_details_callback(mwServiceResolve* srvc, guint32 id, guint32 code, GList* results, gpointer data)
 +{
 +	CSametimeProto* proto = getProtoFromMwServiceResolve(srvc);
 +
 +	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) {
 +
 +				MCONTACT hContact = proto->FindContactByUserId(((mwResolveMatch*)mri->data)->id);
 +				if (hContact) {
 +					char* name = ((mwResolveMatch*)mri->data)->name;
 +					if (name && strlen(name)) {
 +						db_set_utf(hContact, proto->m_szModuleName, "Name", name);
 +						db_set_utf(hContact, proto->m_szModuleName, "Nick", name);
 +						db_set_utf(hContact, "CList", "MyHandle", name);
 +					}
 +				}
 +			}
 +		}
 +	}
 +}
 +
 +
 +int CSametimeProto::SearchForUser(const char* name, BOOLEAN advanced)
 +{
 +	if (m_iStatus != 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_callback, (gpointer)advanced, 0);
 +		g_list_free(query);
 +		return id; // search handle
 +	}
 +	return 0; // fail
 +}
 +
 +
 +int CSametimeProto::GetMoreDetails(const char* name)
 +{
 +	if (m_iStatus != 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_callback, NULL, 0);
 +		g_list_free(query);
 +		return id; // search handle
 +	}
 +	return 0; // fail
 +}
 +
 +
 +INT_PTR CALLBACK CALLBACK SearchDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	switch (msg) {
 +	case WM_INITDIALOG: 
 +		{
 +			TranslateDialogDefault(hwndDlg);
 +			return TRUE;
 +		}
 +	}
 +	return FALSE;
 +}
 +
 +
 +MCONTACT CSametimeProto::AddSearchedUser(MYPROTOSEARCHRESULT* mpsr, bool temporary)
 +{
 +	MCONTACT hContact = 0;
 +	debugLog(_T("CSametimeProto::AddSearchedUser() start"));
 +	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 mwServiceAware_on_attrib_callback(mwServiceAware* srvc, mwAwareAttribute* attrib)
 +{
 +}
 +
 +void mwServiceAware_clear_callback(mwServiceAware* srvc)
 +{
 +}
 +
 +
 +void CSametimeProto::InitUserList()
 +{
 +	debugLog(_T("CSametimeProto::InitUserList()"));
 +
 +	mwSession_addService(session, (mwService*)(service_storage = mwServiceStorage_new(session)));
 +	mwSession_addService(session, (mwService*)(service_resolve = mwServiceResolve_new(session)));
 +	
 +	mwAwareHandler mwAware_handler = {
 +		&mwServiceAware_on_attrib_callback,
 +		&mwServiceAware_clear_callback
 +	};
 +	mwSession_addService(session, (mwService*)(service_aware = mwServiceAware_new(session, &mwAware_handler)));
 +
 +}
 +
 +void CSametimeProto::DeinitUserList()
 +{
 +	debugLog(_T("CSametimeProto::DeinitUserList()"));
 +
 +	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/protocols/Sametime/src/utils.cpp b/protocols/Sametime/src/utils.cpp new file mode 100644 index 0000000000..40e23fbe4a --- /dev/null +++ b/protocols/Sametime/src/utils.cpp @@ -0,0 +1,170 @@ +#include "StdAfx.h"
 +#include "sametime.h"
 +
 +
 +LRESULT CALLBACK PopupWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	switch (msg) 
 +	{
 +		case WM_COMMAND:
 +		{
 +			PUDeletePopup(hWnd);
 +			break;
 +		}
 +
 +		case WM_CONTEXTMENU:
 +			PUDeletePopup(hWnd);
 +			break;
 +
 +		case UM_FREEPLUGINDATA:
 +		{
 +			PopupData* puData = (PopupData*)PUGetPluginData(hWnd);
 +			if (puData != NULL && puData != (PopupData*)CALLSERVICE_NOTFOUND)
 +			{
 +				mir_free(puData->title);
 +				mir_free(puData->text);
 +				mir_free(puData);
 +			}
 +			break;
 +		}
 +	}
 +
 +	return DefWindowProc(hWnd, msg, wParam, lParam);
 +}
 +
 +
 +void CSametimeProto::RegisterPopups()
 +{
 +	TCHAR szDescr[256];
 +	char szName[256];
 +
 +	debugLog(_T("CSametimeProto::RegisterPopups()"));
 +
 +	POPUPCLASS puc = { sizeof(puc) };
 +	puc.PluginWindowProc = PopupWindowProc;
 +	puc.flags = PCF_TCHAR;
 +	puc.ptszDescription = szDescr;
 +	puc.pszName = szName;
 +
 +	mir_snprintf(szName, SIZEOF(szName), "%s_%s", m_szModuleName, "Notify");
 +	mir_sntprintf(szDescr, SIZEOF(szDescr), _T("%s/%s"), m_tszUserName, TranslateT("Notification"));
 +	puc.hIcon = CopyIcon(LoadIconEx("notify", FALSE));
 +	ReleaseIconEx("notify", FALSE);
 +	puc.iSeconds = 8;
 +	puc.colorBack = GetSysColor(COLOR_BTNFACE);
 +	puc.colorText = GetSysColor(COLOR_WINDOWTEXT);
 +	hPopupNotify = Popup_RegisterClass(&puc);
 +
 +	mir_snprintf(szName, SIZEOF(szName), "%s_%s", m_szModuleName, "Error");
 +	mir_sntprintf(szDescr, SIZEOF(szDescr), _T("%s/%s"), m_tszUserName, TranslateT("Error"));
 +	puc.hIcon = CopyIcon(LoadIconEx("error", FALSE));
 +	ReleaseIconEx("error", FALSE);
 +	puc.iSeconds = 10;
 +	puc.colorBack = GetSysColor(COLOR_BTNFACE);
 +	puc.colorText = GetSysColor(COLOR_WINDOWTEXT);
 +	hPopupError = Popup_RegisterClass(&puc);
 +
 +}
 +
 +
 +void CSametimeProto::UnregisterPopups()
 +{
 +	debugLog(_T("CSametimeProto::RegisterPopups()"));
 +	Popup_UnregisterClass(hPopupError);
 +	Popup_UnregisterClass(hPopupNotify);
 +}
 +
 +
 +void CALLBACK sttMainThreadCallback(PVOID dwParam)
 +{
 +
 +	PopupData* puData = (PopupData*)dwParam;
 +	CSametimeProto* proto = puData->proto;
 +
 +	ErrorDisplay disp = proto->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_ADDPOPUPCLASS)) disp = ED_BAL;
 +	if (disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_MB;
 +
 +	if (disp == ED_POP){
 +
 +		POPUPDATACLASS ppd = {sizeof(ppd)};
 +		char szName[256];
 +		ppd.ptszTitle = puData->title;
 +		ppd.ptszText = puData->text;
 +		if (puData->flag == SAMETIME_POPUP_ERROR){
 +			mir_snprintf(szName, SIZEOF(szName), "%s_%s", proto->m_szModuleName, "Error");
 +		} else {
 +			mir_snprintf(szName, SIZEOF(szName), "%s_%s", proto->m_szModuleName, "Notify");
 +		}
 +		CallService(MS_POPUP_ADDPOPUPCLASS, 0, (LPARAM)&ppd);
 +
 +	} else if (disp == ED_BAL) {
 +
 +		MIRANDASYSTRAYNOTIFY sn = { sizeof(sn) };
 +		sn.szProto = proto->m_szModuleName;
 +		sn.tszInfoTitle = puData->title;
 +		sn.tszInfo = puData->text;
 +		sn.dwInfoFlags = NIIF_INTERN_UNICODE;
 +		if (puData->flag == SAMETIME_POPUP_ERROR){
 +			sn.dwInfoFlags = sn.dwInfoFlags | NIIF_WARNING;
 +			sn.uTimeout = 1000 * 10;
 +		} else {
 +			sn.dwInfoFlags = sn.dwInfoFlags | NIIF_INFO;
 +			sn.uTimeout = 1000 * 8;
 +		}
 +		CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&sn);
 +
 +	} else { //disp == ED_MB
 +
 +		if (puData->flag == SAMETIME_POPUP_ERROR){
 +			MessageBox(NULL, puData->text, puData->title, MB_OK | MB_ICONWARNING);
 +		} else {
 +			MessageBox(NULL, puData->text, puData->title, MB_OK | MB_ICONINFORMATION);
 +		}
 +
 +	}
 +
 +	if (disp != ED_POP){
 +		mir_free(puData->title);
 +		mir_free(puData->text);
 +		mir_free(puData);
 +	}
 +
 +}
 +
 +void CSametimeProto::showPopup(const TCHAR* msg, SametimePopupEnum flag)
 +{
 +	if (Miranda_Terminated()) return;
 +
 +	PopupData *puData = (PopupData*)mir_calloc(sizeof(PopupData));
 +	puData->flag = flag;
 +	puData->title = mir_tstrdup(m_tszUserName);
 +	puData->text = mir_tstrdup(msg);
 +	puData->proto = this;
 +
 +	CallFunctionAsync(sttMainThreadCallback, puData);
 +}
 +
 +
 +void LogFromGLib(const gchar* log_domain, GLogLevelFlags log_level, const gchar* message, gpointer user_data)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)user_data;
 +	proto->debugLog(_A2T(message));
 +}
 +
 +void CSametimeProto::RegisterGLibLogger()
 +{
 +	debugLog(_T("CSametimeProto::RegisterGLibLogger"));
 +	gLogHandler = g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_MASK, LogFromGLib, this);
 +}
 +
 +void CSametimeProto::UnRegisterGLibLogger()
 +{
 +	debugLog(_T("CSametimeProto::UnRegisterGLibLogger"));
 +	if (gLogHandler) g_log_remove_handler(G_LOG_DOMAIN, gLogHandler);
 +}
 diff --git a/protocols/Sametime/src/version.h b/protocols/Sametime/src/version.h new file mode 100644 index 0000000000..c66789c5b1 --- /dev/null +++ b/protocols/Sametime/src/version.h @@ -0,0 +1,13 @@ +#define __MAJOR_VERSION           0
 +#define __MINOR_VERSION           7
 +#define __RELEASE_NUM             0
 +#define __BUILD_NUM               0
 +
 +#include <stdver.h>
 +
 +#define __PLUGIN_NAME             "Sametime Protocol"
 +#define __DESCRIPTION             "Implementation of Instant Messaging for the Lotus Sametime protocol."
 +#define __AUTHOR                  "Scott Ellis, Szymon Tokarz"
 +#define __AUTHOREMAIL             "mail"/*antispam*/"@"/*antispam*/"scottellis.com.au, wsx22"/*antispam*/"@"/*antispam*/"o2.pl"
 +#define __COPYRIGHT               "© 2005 Scott Ellis, 2014 wsx22"
 +#define __AUTHORWEB               "http://miranda-ng.org/p/Sametime/"
\ No newline at end of file  | 
